Merge pull request #2597 from matiu/feat/one-view

one page
This commit is contained in:
Gustavo Maximiliano Cortez 2015-04-23 16:35:53 -03:00
commit 3bf7202831
20 changed files with 1104 additions and 546 deletions

View file

@ -78,7 +78,6 @@ module.exports = function(grunt) {
}, },
angular: { angular: {
src: [ src: [
'bower_components/fastclick/lib/fastclick.js',
'bower_components/qrcode-generator/js/qrcode.js', 'bower_components/qrcode-generator/js/qrcode.js',
'bower_components/qrcode-decoder-js/lib/qrcode-decoder.js', 'bower_components/qrcode-decoder-js/lib/qrcode-decoder.js',
'bower_components/moment/min/moment-with-locales.js', 'bower_components/moment/min/moment-with-locales.js',

View file

@ -21,7 +21,6 @@
"angular-bitcore-wallet-client": "^0.0.18", "angular-bitcore-wallet-client": "^0.0.18",
"angular-ui-router": "~0.2.13", "angular-ui-router": "~0.2.13",
"qrcode-decoder-js": "*", "qrcode-decoder-js": "*",
"fastclick": "*",
"angular-ui-switch": "~0.1.0" "angular-ui-switch": "~0.1.0"
}, },
"resolutions": { "resolutions": {

View file

@ -27,7 +27,6 @@
<div notifications="right top"></div> <div notifications="right top"></div>
<div ng-include="'views/includes/offline.html'" ng-if="index.isOffline"></div> <div ng-include="'views/includes/offline.html'" ng-if="index.isOffline"></div>
<div ng-include="'views/includes/clientError.html'" ng-if="index.clientError"></div> <div ng-include="'views/includes/clientError.html'" ng-if="index.clientError"></div>
<div ng-include="'views/includes/password.html'" ng-if="index.askPassword" <div ng-include="'views/includes/password.html'" ng-if="index.askPassword"

View file

@ -1,65 +1 @@
<div class="history" ng-controller="historyController as history">
<div class="row m20t" ng-show="!index.txHistory[0]">
<div class="large-12 columns">
<div class="oh text-center">
<span ng-if="index.updatingTxHistory" class="text-gray animated flash infinite" translate>Getting transactions...</span>
<span ng-if="!index.updatingTxHistory">
<span ng-show="index.txHistoryError && !index.notAuthorized" ng-click='index.openWallet()'>
<span translate>Could not fetch transaction history</span>
<br> [<span translate>Tap to retry</span>]
</span>
<span ng-if="!index.txHistoryError" translate>
No transactions yet
</span>
</span>
</div>
</div>
</div>
<div ng-show="index.txHistory[0]" class="scroll">
<div ng-repeat="btx in index.txHistory"
ng-click="history.openTxModal(btx)"
class="row collapse last-transactions-content">
<div class="large-3 medium-3 small-3 columns">
<span class="label tu radius" ng-show="btx.action == 'received'"
ng-style="{'background-color':index.backgroundColor}" translate>Received</span>
<span class="label tu gray radius" ng-show="btx.action == 'sent'" translate>Sent</span>
<span class="label tu gray radius" ng-show="btx.action == 'moved'" translate>Moved</span>
</div>
<div class="large-5 medium-5 small-5 columns">
<span class="size-16">
<span ng-if="btx.action == 'received'">+</span>
<span ng-if="btx.action == 'sent'">-</span>
{{btx.amountStr}}
{{history.getUnitName()}}
</span>
</div>
<div class="large-4 medium-4 small-4 columns text-right">
<div class="m5t size-12 text-gray">
<time ng-if="btx.time">{{btx.time * 1000 | amTimeAgo}}</time>
<span translate class="text-warning"
ng-show="!btx.time && (!btx.confirmations || btx.confirmations == 0)">
Unconfirmed
</span>
</div>
</div>
<div class="size-14 text-gray columns m5t" ng-if="btx.message || btx.addressTo">
{{btx.message || btx.addressTo}}
</div>
</div>
<div class="m20t row">
<div class="columns">
<button class="outline light-gray small expand" ng-disabled="index.updatingTxHistory"
ng-click="index.updateTxHistory(index.skipHistory)" ng-show="index.txHistoryPaging">
<span ng-show="!index.updatingTxHistory">
<span translate>More</span> <i class="icon-arrow-down4 ng-scope"></i>
</span>
<span ng-show="index.updatingTxHistory" translate>
Getting transactions...
</span>
</button>
</div>
</div>
</div>
</div>
<div class="extra-margin-bottom"></div> <div class="extra-margin-bottom"></div>

View file

@ -4,10 +4,8 @@
<i class="fi-alert"></i> <i class="fi-alert"></i>
</div> </div>
<div class="dr-notification-content"> <div class="dr-notification-content">
<h3 class="dr-notification-title" translate>Wallet Service Error</h3> <h3 class="dr-notification-title">Wallet Service Error</h3>
<div class="dr-notification-text ellipsis"> <div class="dr-notification-text ellipsis">{{index.clientError.message || index.clientError}}</div>
{{index.clientError.error || index.clientError.message || index.clientError}}
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,8 +1,7 @@
<div <div
class="bottom-bar row collapse"> class="bottom-bar row collapse">
<div class="medium-3 small-3 columns text-center bottombar-item" ng-repeat="item in index.menu"> <div class="medium-3 small-3 columns text-center bottombar-item" ng-repeat="item in index.menu">
<a ng-click="$root.go(item.link)" ng-class="{'active': activeMenu == item.link}" <a id="menu-{{item.link}}" ng-click="index.setTab(item.link)" class="{{item.active? 'active': ''}}" style="border-top-color:{{item.active? index.backgroundColor: ''}}" >
ng-style="{'border-top-color':activeMenu==item.link ? index.backgroundColor : ''}">
<i class="size-36 {{item.icon}} db"></i> <i class="size-36 {{item.icon}} db"></i>
<div class="size-10 tu"> <div class="size-10 tu">
{{item.title|translate}} {{item.title|translate}}

View file

@ -1,4 +1,4 @@
<nav ng-controller="topbarController as topbar" class="tab-bar"> <nav ng-controller="topbarController as topbar" class="tab-bar animated fadeIn">
<section class="left-small"> <section class="left-small">
<a class="p10" ng-show="!goBackToState && !index.noFocusedWallet" <a class="p10" ng-show="!goBackToState && !index.noFocusedWallet"
ng-click="index.openMenu()"><i class="fi-list size-24"></i> ng-click="index.openMenu()"><i class="fi-list size-24"></i>

View file

@ -9,15 +9,18 @@
<div class="ellipsis"><b translate>Address</b>: {{uri.address.toString()}}</div> <div class="ellipsis"><b translate>Address</b>: {{uri.address.toString()}}</div>
<div ng-show="uri.amount"><b translate>Amount</b>: {{uri.amount}}</div> <div ng-show="uri.amount"><b translate>Amount</b>: {{uri.amount}}</div>
<div ng-show="uri.message"><b translate>Message</b>: {{uri.message}}</div> <div ng-show="uri.message"><b translate>Message</b>: {{uri.message}}</div>
<div ng-show="uri.network == 'testnet'"><b translate>Network</b>: {{uri.network}}</div>
</div> </div>
<h2 translate>Select a wallet</h2> <h2 translate>Select a wallet</h2>
<ul class="no-bullet" ng-init="wallets = payment.getWallets()"> <ul class="no-bullet" ng-init="wallets = payment.getWallets(uri.network)">
<li class="panel" ng-repeat="w in wallets"> <li class="panel" ng-repeat="w in wallets">
<a ng-click="payment.selectWallet(w.id)"> <a ng-click="payment.selectWallet(w.id)">
<div class="avatar-wallet" <div class="avatar-wallet"
ng-style="{'background-color':w.color}">{{(w.name || w.id) | limitTo: 1}}</div> ng-style="{'background-color':w.color}">{{(w.name || w.id) | limitTo: 1}}</div>
<div class="ellipsis">{{w.name || w.id}}</div> <div class="ellipsis">{{w.name || w.id}}</div>
<div class="size-12">{{w.m}} of {{w.n}}</div> <div class="size-12">{{w.m}} of {{w.n}}
<span ng-show="w.network=='testnet'">[Testnet]</span>
</div>
</a> </a>
</li> </li>
</ul> </ul>

View file

@ -1,70 +1,2 @@
<div class="receive" ng-controller="receiveController as receive" ng-init="receive.getAddress()">
<div ng-show="index.needsBackup && !receive.skipBackup" class="p60t row text-center">
<div class="text-warning text-bold m15b">
<i class="fi-alert"></i>
<span translate>
WARNING: Backup needed
</span>
</div>
<div class="text-gray m15h" translate>
Before receiving funds, it is highly recommended you backup your wallet keys.
</div>
<div class="small-6 columns m20t">
<span class="button expand outline dark-gray tiny"
ng-click="receive.skipBackup = true">
<span translate>SKIP BACKUP</span>
</span>
</div>
<div class="small-6 columns m20t">
<span class="button black expand radius tiny"
ng-click="$root.go('backup')" ng-style="{'background-color':index.backgroundColor}" >
<span translate>Backup now</span>
</span>
</div>
</div>
<div ng-show="!index.needsBackup || receive.skipBackup">
<div class="box-notification" ng-show="receive.error ">
<span class="text-warning size-14">
{{receive.error|translate}}
</span>
</div>
<div class="row" ng-if="receive.addr">
<!-- Address-->
<div class="large-12 columns">
<h2 class="text-center m10t" translate>My Bitcoin address</h2>
<div class="text-center animated fadeIn" ng-click="receive.copyAddress(receive.addr)">
<qrcode size="220" data="bitcoin:{{receive.addr}}"></qrcode>
<div class="m10t">
<h4 ng-class="{'enable_text_select': !index.isCordova}" class="size-12">{{receive.addr}}</h4>
</div>
</div>
<div class="m10t text-center" ng-show="index.isCordova">
<span class="button outline dark-gray tiny"
ng-click="receive.shareAddress(receive.addr)">
<i class="fi-share"></i>
<span translate>Share address</span>
</span>
</div>
<div class="line-t size-12" translate>
Share this with anyone to have them send you payments. To protect your privacy, new addresses are generated automatically once you use them.
</div>
</div>
</div>
<div class="row m20t" ng-if="receive.addr">
<div class="large-12 columns">
<button class="button black expand radius" ng-click="receive.newAddress()"
ng-style="{'background-color':index.backgroundColor}" ng-disabled="receive.generatingAddress" translate>
Generate new address
</button>
</div>
</div>
</div>
</div>
<div class="extra-margin-bottom"></div> <div class="extra-margin-bottom"></div>

View file

@ -1,117 +1,405 @@
<div class="home-wallet" ng-controller="walletHomeController as home"> <div ng-controller="walletHomeController as home">
<div class="oh" ng-show="!index.noFocusedWallet"> <div id="walletHome" class="walletHome tab-view tab-in">
<div class="amount" ng-style="{'background-color':index.backgroundColor}"> <div class="oh" ng-show="!index.noFocusedWallet">
<div ng-if="!index.anyOnGoingProcess && !index.notAuthorized"> <div class="amount" ng-style="{'background-color':index.backgroundColor}">
<div ng-show="index.updateError" ng-click='index.openWallet()'> <div ng-if="!index.anyOnGoingProcess && !index.notAuthorized">
<span translate>Could not update Wallet</span> <div ng-show="index.updateError" ng-click='index.openWallet()'>
<br><span translate>Tap to retry</span> <span translate>Could not update Wallet</span>
</div> <br><span translate>Tap to retry</span>
<div ng-show="index.walletScanStatus == 'error'" ng-click='index.retryScan()'>
<span translate>Scan status finished with error</span>
<br><span translate>Tap to retry</span>
</div>
<div ng-show="!index.updateError && index.walletScanStatus != 'error'">
<div class="size-36 animated fadeIn">
<strong>{{index.totalBalanceStr}}</strong>
</div> </div>
<div class="size-14"
ng-if="index.totalBalanceAlternative"> <div ng-show="index.walletScanStatus == 'error'" ng-click='index.retryScan()'>
<span ng-class="{'animated fadeIn':!index.hideBalance}"> <span translate>Scan status finished with error</span>
<br><span translate>Tap to retry</span>
</div>
<div ng-show="!index.updateError && index.walletScanStatus != 'error'">
<strong class="size-36">{{index.totalBalanceStr}}</strong>
<div class="size-14"
ng-if="index.totalBalanceAlternative">
{{index.totalBalanceAlternative}} {{index.alternativeIsoCode}} {{index.totalBalanceAlternative}} {{index.alternativeIsoCode}}
</span> </div>
</div>
</div>
<div ng-if="index.anyOnGoingProcess">
<div class="size-36">
<strong>...</strong>
</div> </div>
</div> </div>
</div> </div>
<div class="pr columns line-b">
<div ng-if="index.anyOnGoingProcess"> <div class="avatar-wallet left"
<div class="size-36"> ng-style="{'background-color':index.backgroundColor}">{{index.walletName | limitTo: 1}}</div>
<strong>...</strong> <div class="right">
<a ng-click="$root.go('preferences')" class="button outline light-gray tiny m0">
<i class="fi-widget size-18 vm"></i>
<span class="show-for-medium-up" translate>Preferences</span>
</a>
</div> </div>
<div class="wallet-info" ng-click="openCopayersModal(index.copayers, index.copayerId)">
<p class="m0">
{{index.m}} <span translate>of</span> {{index.n}}
</p>
<div class="size-12 text-gray">
<span ng-if="index.n > 1" translate>Multisignature wallet </span>
<span ng-if="index.n == 1" translate>Personal Wallet</span>
<span ng-if="index.network != 'livenet'"> - Testnet</span>
</div>
</div>
</div> </div>
</div> </div>
<div class="pr columns line-b">
<div class="avatar-wallet left" <div class="onGoingProcess"
ng-class="{'updating':index.anyOnGoingProcess}" ng-show="index.anyOnGoingProcess"
ng-style="{'background-color':index.backgroundColor}">{{index.walletName | limitTo: 1}}</div> ng-style="{'background-color':index.backgroundColor}"
<div class="right"> ng-class="{'opacityCycle':index.anyOnGoingProcess}"
<a ng-click="$root.go('preferences')" class="button outline light-gray tiny m0"> >
<i class="fi-widget size-18 vm"></i> <span translate ng-show="index.onGoingProcessName == 'openingWallet'">Opening Wallet...</span>
<span class="show-for-medium-up" translate>Preferences</span> <span translate ng-show="index.onGoingProcessName == 'updatingStatus'">Updating Status...</span>
</a> <span translate ng-show="index.onGoingProcessName == 'updatingBalance'">Updating Balance...</span>
<span translate ng-show="index.onGoingProcessName == 'updatingPendingTxps'">Updating Pending Transactions...</span>
<span translate ng-show="index.onGoingProcessName == 'scanning'">Scanning Wallet funds...</span>
<span translate ng-show="index.onGoingProcessName == 'recreating'">Recreating Wallet on BWS...</span>
</div>
<div class="m20t" ng-show="index.notAuthorized">
<div class="text-center text-warning">
<i class="fi-alert"></i>
<span translate>
WARNING: Wallet not registered
</span>
</div>
<div class="text-center text-gray m15r m15l" translate>
This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.
</div>
<div class="text-center m10t ">
<span class="button outline dark-gray tiny"
ng-click="index.recreate()">
<span translate>Recreate</span>
</span>
</div>
</div>
<div ng-show="index.requiresMultipleSignatures && index.txps[0]">
<h4 class="title m0" translate>Spend proposals</h4>
<div class="last-transactions pr" ng-repeat="tx in index.txps"
ng-include="'views/includes/transaction.html'">
</div>
<div class="text-gray text-center size-12 p10t"
ng-show="index.lockedBalance && !index.updatingStatus">
<span translate>Total Locked Balance</span>:
<b>{{index.lockedBalance}} {{index.unitName}} </b>
<span> {{index.lockedBalanceAlternative}}
{{index.alternativeIsoCode}} </span>
</div>
<div class="pr" ng-if="!index.txps[0]">
<p translate>No pending spend proposals at the moment.</p>
</div>
</div>
<div ng-if="!index.requiresMultipleSignatures && index.txps[0]">
<h4 class="title m0" translate>Unsent transactions</h4>
<div class="last-transactions pr" ng-repeat="tx in index.txps"
ng-include="'views/includes/transaction.html'">
</div> </div>
<div class="wallet-info" ng-click="openCopayersModal(index.copayers, index.copayerId)">
<p class="m0">
{{index.m}} <span translate>of</span> {{index.n}}
</p>
<div class="size-12 text-gray">
<span ng-if="index.n > 1" translate>Multisignature wallet </span>
<span ng-if="index.n == 1" translate>Personal Wallet</span>
<span ng-if="index.network != 'livenet'"> - Testnet</span>
</div>
</div>
</div> </div>
</div> </div>
<div class="onGoingProcess" <!--
ng-show="index.anyOnGoingProcess"
ng-style="{'background-color':index.backgroundColor}"
ng-class="{'opacityCycle':index.anyOnGoingProcess}"
>
<span translate ng-show="index.onGoingProcessName == 'openingWallet'">Opening Wallet...</span>
<span translate ng-show="index.onGoingProcessName == 'updatingStatus'">Updating Status...</span>
<span translate ng-show="index.onGoingProcessName == 'updatingBalance'">Updating Balance...</span>
<span translate ng-show="index.onGoingProcessName == 'updatingPendingTxps'">Updating Pending Transactions...</span>
<span translate ng-show="index.onGoingProcessName == 'scanning'">Scanning Wallet funds...</span>
<span translate ng-show="index.onGoingProcessName == 'recreating'">Recreating Wallet on BWS...</span>
</div>
<div class="m20t" ng-show="index.notAuthorized"> receive
<div class="text-center text-warning">
-->
<div id="receive" class="receive tab-view">
<div ng-show="index.needsBackup && !home.skipBackup" class="p60t row text-center">
<div class="text-warning text-bold m15b">
<i class="fi-alert"></i> <i class="fi-alert"></i>
<span translate> <span translate>
WARNING: Wallet not registered WARNING: Backup needed
</span> </span>
</div> </div>
<div class="text-center text-gray m15r m15l" translate> <div class="text-gray m15h" translate>
This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information. Before receiving funds, it is highly recommended you backup your wallet keys.
</div> </div>
<div class="text-center m10t ">
<span class="button outline dark-gray tiny" <div class="small-6 columns m20t">
ng-click="index.recreate()"> <span class="button expand outline dark-gray tiny"
<span translate>Recreate</span> ng-click="home.skipBackup = true">
<span translate>SKIP BACKUP</span>
</span>
</div>
<div class="small-6 columns m20t">
<span class="button black expand radius tiny"
ng-click="$root.go('backup')" ng-style="{'background-color':index.backgroundColor}" >
<span translate>Backup now</span>
</span> </span>
</div> </div>
</div> </div>
<div ng-show="!index.needsBackup || home.skipBackup">
<div class="box-notification" ng-show="home.error ">
<div ng-show="index.requiresMultipleSignatures && index.txps[0]"> <span class="text-warning size-14">
<h4 class="title m0" translate>Spend proposals</h4> {{home.error|translate}}
<div class="last-transactions pr" ng-repeat="tx in index.txps" </span>
ng-include="'views/includes/transaction.html'">
</div> </div>
<div class="row" ng-if="home.addr">
<div class="text-gray text-center size-12 p10t" <!-- Address-->
ng-show="index.lockedBalance && !index.updatingStatus"> <div class="large-12 columns">
<span translate>Total Locked Balance</span>: <h2 class="text-center m10t" translate>My Bitcoin address</h2>
<b>{{index.lockedBalance}} {{index.unitName}} </b> <div class="text-center" ng-click="home.copyAddress(home.addr)">
<span> {{index.lockedBalanceAlternative}} <qrcode size="220" data="bitcoin:{{home.addr}}"></qrcode>
{{index.alternativeIsoCode}} </span> <div class="m10t">
<h4 ng-class="{'enable_text_select': !index.isCordova}" class="size-12">{{home.addr}}</h4>
</div>
</div>
<div class="m10t text-center" ng-show="index.isCordova">
<span class="button outline dark-gray tiny"
ng-click="home.shareAddress(home.addr)">
<i class="fi-share"></i>
<span translate>Share address</span>
</span>
</div>
<div class="line-t size-12" translate>
Share this with anyone to have them send you payments. To protect your privacy, new addresses are generated automatically once you use them.
</div>
</div>
</div> </div>
<div class="row m20t" ng-if="home.addr">
<div class="pr" ng-if="!index.txps[0]"> <div class="large-12 columns">
<p translate>No pending spend proposals at the moment.</p> <button class="button black expand radius" ng-click="home.newAddress()"
ng-style="{'background-color':index.backgroundColor}" ng-disabled="home.generatingAddress" translate>
Generate new address
</button>
</div>
</div> </div>
</div> </div>
<div ng-if="!index.requiresMultipleSignatures && index.txps[0]"> </div>
<h4 class="title m0" translate>Unsent transactions</h4>
<div class="last-transactions pr" ng-repeat="tx in index.txps"
ng-include="'views/includes/transaction.html'"> <!--
</div>
send
-->
<div id="send" class="send tab-view">
<div ng-show="index.lockedBalance">
<h4 class="title m0">
<div class="left">
<i class="fi-info size-36 m10r lh"></i>
</div>
<div class="size-12">
<span class="db text-bold">
<span translate>Available Balance</span>:
{{index.availableBalanceStr }}
</span>
<span class="text-gray">
{{index.lockedBalanceStr}}
<span translate>in pending transactions</span>
</span>
</div>
</h4>
</div>
<div class="row m20t">
<div class="large-12 large-centered columns">
<div class="box-notification" ng-show="home.fetchingURL">
<span class="text-secondary size-14" translate>
Fetching Payment Information...
</span>
</div>
<form ng-show="!home.fetchingURL" name="sendForm" ng-submit="home.submitForm(sendForm)" ng-disabled="home.blockUx" novalidate>
<div class="box-notification" ng-show="home.error" ng-click="home.resetError()">
<span class="text-warning">
{{home.error|translate}}
</span>
<a class="close-notification text-warning">&#215;</a>
</div>
<div ng-hide="home._paypro || home.hideAddress">
<div class="row collapse">
<label for="address" class="left" >
<span translate>To</span>
</label>
<span ng-hide="sendForm.address.$pristine">
<span class="has-error right size-12" ng-show="sendForm.address.$invalid && _address">
<span class="icon-input">
<i class="fi-x"></i>
</span>
<span translate>Not valid</span>
</span>
<small class="icon-input right" ng-show="!sendForm.address.$invalid">
<i class="fi-check"></i>
</small>
</span>
</div>
<div class="input">
<input type="text" id="address" name="address" ng-disabled="home.blockUx || home.lockAddress" ng-attr-placeholder="{{'Bitcoin address'|translate}}" ng-model="_address" valid-address required ng-focus="home.formFocus('address')" ng-blur="home.formFocus(false)">
</div>
</div>
<div ng-show="home._paypro && !home.hideAddress">
<div class="row collapse" ng-click="home.openPPModal(home._paypro)">
<label for="domain">
<span translate>Payment to</span>
</label>
<div class="input block">
<input class="p45li" type="text" id="domain" name="domain" ng-model="home._paypro.domain" ng-disabled="1">
<i ng-show="home._paypro.verified" class="fi-lock color-greeni"></i>
<i ng-show="!home._paypro.verified" class="fi-unlock color-yellowi"></i>
</div>
</div>
</div>
<div class="row" ng-init="showAlternative = false" ng-hide="home.hideAmount">
<div class="large-12 medium-12 columns">
<div class="m5b right" ng-hide="sendForm.amount.$pristine">
<span class="has-error right size-12" ng-show="sendForm.amount.$invalid">
<span class="icon-input"><i class="fi-x"></i></span>
<span translate>Not valid</span>
</span>
<small class="icon-input right" ng-show="!sendForm.amount.$invalid">
<i class="fi-check"></i>
</small>
</div>
<div ng-show="!showAlternative">
<label for="amount">
<span translate>Amount</span>
</label>
<div class="input">
<input type="number" id="amount" ng-disabled="home.blockUx || home.lockAmount" name="amount" ng-attr-placeholder="{{'Amount'|translate}}" ng-minlength="0.00000001" ng-maxlength="10000000000" ng-model="_amount" valid-amount required autocomplete="off" ng-focus="home.formFocus('amount')" ng-blur="home.formFocus(false)">
<a class="postfix" ng-click="showAlternative = true">{{home.unitName}}</a>
</div>
</div>
<div ng-show="showAlternative">
<label for="alternative"><span translate>Amount in</span> {{ home.alternativeName }}
</label>
<div class="input">
<input type="number" id="alternative" ng-disabled="home.blockUx || !home.isRateAvailable || home.lockAmount" name="alternative" ng-attr-placeholder="{{'Amount'|translate}}" ng-model="_alternative" requiredautocomplete="off" ng-focus="home.formFocus('amount')" ng-blur="home.formFocus(false)">
<a class="postfix" ng-click="showAlternative = false"> {{ home.alternativeIsoCode }}</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<label for="comment"><span translate>Note</span>
<small translate ng-hide="!sendForm.comment.$pristine">optional</small>
<small translate class="has-error" ng-show="sendForm.comment.$invalid && !sendForm.comment.$pristine">too long!</small>
</label>
<div class="input">
<textarea id="comment" ng-disabled="home.blockUx" name="comment"
ng-maxlength="100" ng-model="_comment" ng-focus="home.formFocus('msg')"
ng-blur="home.formFocus(false)"></textarea>
</div>
</div>
</div>
<div ng-if="home.onGoingProcess" class="text-gray text-center m10t">
<span class="animated infinite flash">{{home.onGoingProcess|translate}}...</span>
</div> </div>
<div class="row" ng-show="!home.onGoingProcess">
<div class="large-6 medium-6 small-6 columns" ng-show="!home.blockUx && (home._paypro || home.lockAddress)">
<a ng-click="home.resetForm(sendForm)" class="button expand outline dark-gray" translate>Cancel</a>
</div>
<div class="columns" ng-class="{'small-6 medium-6 large-6':(home._paypro || home.lockAddress)}">
<button type="submit" class="button black radius expand" ng-disabled="sendForm.$invalid || home.blockUx"
ng-style="{'background-color':index.backgroundColor}" translate>
Send
</button>
</div>
</div>
</form>
</div>
</div>
<!-- end of row -->
</div>
<!--
history
-->
<div id="history" class="history tab-view">
<div class="row m20t" ng-show="!index.txHistory[0]">
<div class="large-12 columns">
<div class="oh text-center">
<span ng-if="index.updatingTxHistory" class="text-gray animated flash infinite" translate>Getting transactions...</span>
<span ng-if="!index.updatingTxHistory">
<span ng-show="index.txHistoryError && !index.notAuthorized" ng-click='index.openWallet()'>
<span translate>Could not fetch transaction history</span>
<br> [<span translate>Tap to retry</span>]
</span>
<span ng-if="!index.txHistoryError" translate>
No transactions yet
</span>
</span>
</div>
</div>
</div>
<div ng-show="index.txHistory[0]" class="scroll">
<div ng-repeat="btx in index.txHistory"
ng-click="home.openTxModal(btx)"
class="row collapse last-transactions-content">
<div class="large-3 medium-3 small-3 columns">
<span class="label tu radius" ng-show="btx.action == 'received'"
ng-style="{'background-color':index.backgroundColor}" translate>Received</span>
<span class="label tu gray radius" ng-show="btx.action == 'sent'" translate>Sent</span>
<span class="label tu gray radius" ng-show="btx.action == 'moved'" translate>Moved</span>
</div>
<div class="large-5 medium-5 small-5 columns">
<span class="size-16">
<span ng-if="btx.action == 'received'">+</span>
<span ng-if="btx.action == 'sent'">-</span>
{{btx.amountStr}}
{{home.getUnitName()}}
</span>
</div>
<div class="large-4 medium-4 small-4 columns text-right">
<div class="m5t size-12 text-gray">
<time ng-if="btx.time">{{btx.time * 1000 | amTimeAgo}}</time>
<span translate class="text-warning"
ng-show="!btx.time && (!btx.confirmations || btx.confirmations == 0)">
Unconfirmed
</span>
</div>
</div>
<div class="size-14 text-gray columns m5t" ng-if="btx.message || btx.addressTo">
{{btx.message || btx.addressTo}}
</div>
</div>
<div class="m20t row">
<div class="columns">
<button class="outline light-gray small expand" ng-disabled="index.updatingTxHistory"
ng-click="index.updateTxHistory(index.skipHistory)" ng-show="index.txHistoryPaging">
<span ng-show="!index.updatingTxHistory">
<span translate>More</span> <i class="icon-arrow-down4 ng-scope"></i>
</span>
<span ng-show="index.updatingTxHistory" translate>
Getting transactions...
</span>
</button>
</div>
</div>
</div>
</div>
<!-- END -->
<div class="row columns m20tp" ng-show="index.noFocusedWallet"> <div class="row columns m20tp" ng-show="index.noFocusedWallet">
<div class="text-center text-warning m20b"> <div class="text-center text-warning m20b">
<i class="fi-alert"></i> <span translate>You do not have any wallet</span> <i class="fi-alert"></i> <span translate>You do not have any wallet</span>

View file

@ -144,6 +144,7 @@ input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill, inpu
.main { .main {
background-color: #fff; background-color: #fff;
padding: 45px 0 80px 0; padding: 45px 0 80px 0;
position: relative;
} }
.logo-setup { .logo-setup {
@ -1106,104 +1107,6 @@ input.ng-invalid-match, input.ng-invalid-match:focus {
cursor: pointer !important; cursor: pointer !important;
} }
.updating {
-webkit-animation-iteration-count: infinite;
-webkit-animation-name: up-animation;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
animation-name: up-animation;
animation-duration: 1s;
animation-iteration-count: infinite;
}
/* Generated with Bounce.js. Edit at http://goo.gl/Vn2Euz */
@-webkit-keyframes up-animation {
0% { -webkit-transform: matrix3d(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
3.4% { -webkit-transform: matrix3d(0.658, 0, 0, 0, 0, 0.703, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.658, 0, 0, 0, 0, 0.703, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
4.7% { -webkit-transform: matrix3d(0.725, 0, 0, 0, 0, 0.8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.725, 0, 0, 0, 0, 0.8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
6.81% { -webkit-transform: matrix3d(0.83, 0, 0, 0, 0, 0.946, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.83, 0, 0, 0, 0, 0.946, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
9.41% { -webkit-transform: matrix3d(0.942, 0, 0, 0, 0, 1.084, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.942, 0, 0, 0, 0, 1.084, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
10.21% { -webkit-transform: matrix3d(0.971, 0, 0, 0, 0, 1.113, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.971, 0, 0, 0, 0, 1.113, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
13.61% { -webkit-transform: matrix3d(1.062, 0, 0, 0, 0, 1.166, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.062, 0, 0, 0, 0, 1.166, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
14.11% { -webkit-transform: matrix3d(1.07, 0, 0, 0, 0, 1.165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.07, 0, 0, 0, 0, 1.165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
17.52% { -webkit-transform: matrix3d(1.104, 0, 0, 0, 0, 1.12, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.104, 0, 0, 0, 0, 1.12, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
18.72% { -webkit-transform: matrix3d(1.106, 0, 0, 0, 0, 1.094, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.106, 0, 0, 0, 0, 1.094, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
21.32% { -webkit-transform: matrix3d(1.098, 0, 0, 0, 0, 1.035, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.098, 0, 0, 0, 0, 1.035, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
24.32% { -webkit-transform: matrix3d(1.075, 0, 0, 0, 0, 0.98, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.075, 0, 0, 0, 0, 0.98, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
25.23% { -webkit-transform: matrix3d(1.067, 0, 0, 0, 0, 0.969, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.067, 0, 0, 0, 0, 0.969, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
29.03% { -webkit-transform: matrix3d(1.031, 0, 0, 0, 0, 0.948, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.031, 0, 0, 0, 0, 0.948, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
29.93% { -webkit-transform: matrix3d(1.024, 0, 0, 0, 0, 0.949, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.024, 0, 0, 0, 0, 0.949, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
35.54% { -webkit-transform: matrix3d(0.99, 0, 0, 0, 0, 0.981, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.99, 0, 0, 0, 0, 0.981, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
36.74% { -webkit-transform: matrix3d(0.986, 0, 0, 0, 0, 0.989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.986, 0, 0, 0, 0, 0.989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
41.04% { -webkit-transform: matrix3d(0.98, 0, 0, 0, 0, 1.011, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.98, 0, 0, 0, 0, 1.011, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
44.44% { -webkit-transform: matrix3d(0.983, 0, 0, 0, 0, 1.016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.983, 0, 0, 0, 0, 1.016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
52.15% { -webkit-transform: matrix3d(0.996, 0, 0, 0, 0, 1.003, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.996, 0, 0, 0, 0, 1.003, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
59.86% { -webkit-transform: matrix3d(1.003, 0, 0, 0, 0, 0.995, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.003, 0, 0, 0, 0, 0.995, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
63.26% { -webkit-transform: matrix3d(1.004, 0, 0, 0, 0, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.004, 0, 0, 0, 0, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
75.28% { -webkit-transform: matrix3d(1.001, 0, 0, 0, 0, 1.002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.001, 0, 0, 0, 0, 1.002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
85.49% { -webkit-transform: matrix3d(0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
90.69% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
100% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
}
@keyframes up-animation {
0% { transform: matrix3d(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
3.4% { transform: matrix3d(0.658, 0, 0, 0, 0, 0.703, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.658, 0, 0, 0, 0, 0.703, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
4.7% { transform: matrix3d(0.725, 0, 0, 0, 0, 0.8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.725, 0, 0, 0, 0, 0.8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
6.81% { transform: matrix3d(0.83, 0, 0, 0, 0, 0.946, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.83, 0, 0, 0, 0, 0.946, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
9.41% { transform: matrix3d(0.942, 0, 0, 0, 0, 1.084, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.942, 0, 0, 0, 0, 1.084, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
10.21% { transform: matrix3d(0.971, 0, 0, 0, 0, 1.113, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.971, 0, 0, 0, 0, 1.113, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
13.61% { transform: matrix3d(1.062, 0, 0, 0, 0, 1.166, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.062, 0, 0, 0, 0, 1.166, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
14.11% { transform: matrix3d(1.07, 0, 0, 0, 0, 1.165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.07, 0, 0, 0, 0, 1.165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
17.52% { transform: matrix3d(1.104, 0, 0, 0, 0, 1.12, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.104, 0, 0, 0, 0, 1.12, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
18.72% { transform: matrix3d(1.106, 0, 0, 0, 0, 1.094, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.106, 0, 0, 0, 0, 1.094, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
21.32% { transform: matrix3d(1.098, 0, 0, 0, 0, 1.035, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.098, 0, 0, 0, 0, 1.035, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
24.32% { transform: matrix3d(1.075, 0, 0, 0, 0, 0.98, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.075, 0, 0, 0, 0, 0.98, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
25.23% { transform: matrix3d(1.067, 0, 0, 0, 0, 0.969, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.067, 0, 0, 0, 0, 0.969, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
29.03% { transform: matrix3d(1.031, 0, 0, 0, 0, 0.948, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.031, 0, 0, 0, 0, 0.948, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
29.93% { transform: matrix3d(1.024, 0, 0, 0, 0, 0.949, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.024, 0, 0, 0, 0, 0.949, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
35.54% { transform: matrix3d(0.99, 0, 0, 0, 0, 0.981, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.99, 0, 0, 0, 0, 0.981, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
36.74% { transform: matrix3d(0.986, 0, 0, 0, 0, 0.989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.986, 0, 0, 0, 0, 0.989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
41.04% { transform: matrix3d(0.98, 0, 0, 0, 0, 1.011, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.98, 0, 0, 0, 0, 1.011, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
44.44% { transform: matrix3d(0.983, 0, 0, 0, 0, 1.016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.983, 0, 0, 0, 0, 1.016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
52.15% { transform: matrix3d(0.996, 0, 0, 0, 0, 1.003, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.996, 0, 0, 0, 0, 1.003, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
59.86% { transform: matrix3d(1.003, 0, 0, 0, 0, 0.995, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.003, 0, 0, 0, 0, 0.995, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
63.26% { transform: matrix3d(1.004, 0, 0, 0, 0, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.004, 0, 0, 0, 0, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
75.28% { transform: matrix3d(1.001, 0, 0, 0, 0, 1.002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.001, 0, 0, 0, 0, 1.002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
85.49% { transform: matrix3d(0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
90.69% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
100% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
}
.opacityCycle {
-webkit-animation-iteration-count: infinite;
-webkit-animation-name: opCycle-animation;
-webkit-animation-duration: 20s;
-webkit-animation-iteration-count: infinite;
}
@-webkit-keyframes opCycle-animation
{
0% {opacity:1}
15% {opacity:0.7}
30% {opacity:0.85}
45% {opacity:0.5}
60% {opacity:0.8}
75% {opacity:0.7}
99% {opacity:1;}
}
.onGoingProcess { .onGoingProcess {
text-align: center; text-align: center;
max-width: 14.5rem; max-width: 14.5rem;
@ -1211,7 +1114,7 @@ input.ng-invalid-match, input.ng-invalid-match:focus {
top:auto; top:auto;
left:0; left:0;
right:0; right:0;
bottom:90px; bottom: 130px;
margin: auto; margin: auto;
border-radius: 3px; border-radius: 3px;
color: #fff; color: #fff;

View file

@ -172,11 +172,11 @@ _:-ms-fullscreen, :root .main {
height:100%; height:100%;
} }
.home-wallet { .walletHome {
background-color: #fff; background-color: #fff;
} }
.home-wallet .avatar-wallet { .walletHome .avatar-wallet {
padding: 1.7rem 1rem; padding: 1.7rem 1rem;
width: 75px; width: 75px;
height: 75px; height: 75px;
@ -193,7 +193,7 @@ _:-ms-fullscreen, :root .main {
border-radius: 5px; border-radius: 5px;
} }
.home-wallet .wallet-info { .walletHome .wallet-info {
margin-left: 85px; margin-left: 85px;
line-height: 110%; line-height: 110%;
float: left; float: left;
@ -642,24 +642,22 @@ a.pin-button:active {
.animation-left.ng-enter, .animation-left.ng-leave, .animation-left.ng-enter, .animation-left.ng-leave,
.animation-right.ng-enter, .animation-right.ng-leave { .animation-right.ng-enter, .animation-right.ng-leave {
-webkit-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 250ms; -webkit-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 300ms;
-moz-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 250ms; -moz-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 300ms;
-ms-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 250ms; -ms-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 300ms;
-o-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 250ms; -o-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 300ms;
transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 250ms; transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 300ms;
} }
.animation-left.ng-enter { .animation-left.ng-enter {
-webkit-transform: translate3d(100%, 0, 0); -webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0);
-webkit-transition-delay: 0.05s; opacity: 0.6;
opacity: 0;
} }
.animation-right.ng-enter { .animation-right.ng-enter {
-webkit-transform: translate3d(-100%, 0, 0); -webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0);
-webkit-transition-delay: 0.05s; opacity: 0.6;
opacity: 0;
} }
.animation-left.ng-enter.ng-enter-active, .animation-left.ng-enter.ng-enter-active,
.animation-right.ng-enter.ng-enter-active { .animation-right.ng-enter.ng-enter-active {
@ -672,18 +670,37 @@ a.pin-button:active {
.animation-right.ng-leave { .animation-right.ng-leave {
-webkit-transform: translate3d(0, 0, 0); -webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0);
opacity: 0; opacity: 0.6;
} }
.animation-left.ng-leave.animation-left.ng-leave-active { .animation-left.ng-leave.animation-left.ng-leave-active {
-webkit-transform: translate3d(-100%, 0, 0); -webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0);
-webkit-transition-delay: 0.05s; opacity: 0.6;
opacity: 0;
} }
.animation-right.ng-leave.animation-right.ng-leave-active { .animation-right.ng-leave.animation-right.ng-leave-active {
-webkit-transform: translate3d(100%, 0, 0); -webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0);
-webkit-transition-delay: 0.05s; opacity: 0.6;
opacity: 0;
} }
.tab-view {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
width:100%;
position: absolute;
margin-bottom: 50px;
height: 100%;
}
.tab-in {
-webkit-transform: translate3d(0, 0, 0) !important;
transform: translate3d(0, 0, 0) !important;
}
.tab-out {
-webkit-transform: translate3d(-100%, 0, 0) !important;
transform: translate3d(-100%, 0, 0) !important;
}

View file

@ -3,76 +3,4 @@
angular.module('copayApp.controllers').controller('historyController', angular.module('copayApp.controllers').controller('historyController',
function($scope, $rootScope, $filter, $timeout, $modal, $log, profileService, notification, go, configService, rateService, lodash) { function($scope, $rootScope, $filter, $timeout, $modal, $log, profileService, notification, go, configService, rateService, lodash) {
function strip(number) {
return (parseFloat(number.toPrecision(12)));
}
var fc = profileService.focusedClient;
var config = configService.getSync().wallet.settings;
this.unitToSatoshi = config.unitToSatoshi;
this.satToUnit = 1 / this.unitToSatoshi;
this.unitName = config.unitName;
this.alternativeIsoCode = config.alternativeIsoCode;
this.getUnitName = function() {
return this.unitName;
};
this.getAlternativeIsoCode = function() {
return this.alternativeIsoCode;
};
this._addRates = function(txs, cb) {
if (!txs || txs.length == 0) return cb();
var index = lodash.groupBy(txs, 'rateTs');
rateService.getHistoricRates(config.alternativeIsoCode, lodash.keys(index), function(err, res) {
if (err || !res) return cb(err);
lodash.each(res, function(r) {
lodash.each(index[r.ts], function(tx) {
var alternativeAmount = (r.rate != null ? tx.amount * rateService.SAT_TO_BTC * r.rate : null);
tx.alternativeAmount = alternativeAmount ? $filter('noFractionNumber')(alternativeAmount, 2) : null;
});
});
return cb();
});
};
this.openTxModal = function(btx) {
var self = this;
var fc = profileService.focusedClient;
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.btx = btx;
$scope.settings = config;
$scope.color = fc.backgroundColor;
$scope.getAmount = function(amount) {
return self.getAmount(amount);
};
$scope.getUnitName = function() {
return self.getUnitName();
};
$scope.getShortNetworkName = function() {
var n = fc.credentials.network;
return n.substring(0, 4);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
$modal.open({
templateUrl: 'views/modals/tx-details.html',
windowClass: 'full',
controller: ModalInstanceCtrl,
});
};
this.hasAction = function(actions, action) {
return actions.hasOwnProperty('create');
};
}); });

View file

@ -4,7 +4,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
var self = this; var self = this;
self.isCordova = isCordova; self.isCordova = isCordova;
self.onGoingProcess = {}; self.onGoingProcess = {};
self.limitHistory = 5; self.limitHistory = 5;
function strip(number) { function strip(number) {
return (parseFloat(number.toPrecision(12))); return (parseFloat(number.toPrecision(12)));
@ -13,7 +13,8 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.menu = [{ self.menu = [{
'title': 'Home', 'title': 'Home',
'icon': 'icon-home', 'icon': 'icon-home',
'link': 'walletHome' 'link': 'walletHome',
'active': true,
}, { }, {
'title': 'Receive', 'title': 'Receive',
'icon': 'icon-receive', 'icon': 'icon-receive',
@ -26,7 +27,9 @@ angular.module('copayApp.controllers').controller('indexController', function($r
'title': 'History', 'title': 'History',
'icon': 'icon-history', 'icon': 'icon-history',
'link': 'history' 'link': 'history'
}]; }];
self.tab = 'walletHome';
self.availableLanguages = [{ self.availableLanguages = [{
name: 'English', name: 'English',
@ -100,6 +103,34 @@ angular.module('copayApp.controllers').controller('indexController', function($r
}); });
}; };
self.setTab = function(tab) {
if (self.tab === tab)
return;
if (!self.tab)
self.tab = 'walletHome';
if (document.getElementById(self.tab)) {
document.getElementById(self.tab).className = 'tab-out tab-view ' + self.tab;
var old = document.getElementById('menu-' + self.tab);
if (old) {
old.className = '';
old.style.borderTopColor = '';
}
}
if (document.getElementById(tab)) {
document.getElementById(tab).className = 'tab-in tab-view ' + tab;
var newe = document.getElementById('menu-' + tab);
newe.className = 'active';
newe.style.borderTopColor = self.backgroundColor;
}
self.tab = tab;
$rootScope.$emit('Local/TabChanged', tab);
};
self.updateAll = function(walletStatus) { self.updateAll = function(walletStatus) {
var get = function(cb) { var get = function(cb) {
if (walletStatus) if (walletStatus)
@ -223,8 +254,8 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.openWallet = function() { self.openWallet = function() {
var fc = profileService.focusedClient; var fc = profileService.focusedClient;
self.updateColor(); self.updateColor();
$rootScope.$apply();
$timeout(function() { $timeout(function() {
$rootScope.$apply();
self.setOngoingProcess('openingWallet', true); self.setOngoingProcess('openingWallet', true);
self.updateError = false; self.updateError = false;
fc.openWallet(function(err, walletStatus) { fc.openWallet(function(err, walletStatus) {
@ -454,8 +485,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
gettextCatalog.setCurrentLanguage(userLang); gettextCatalog.setCurrentLanguage(userLang);
amMoment.changeLocale(userLang); amMoment.changeLocale(userLang);
} }
} } else {
else {
configService.set({ configService.set({
wallet: { wallet: {
settings: { settings: {
@ -468,7 +498,9 @@ angular.module('copayApp.controllers').controller('indexController', function($r
}); });
} }
self.defaultLanguageIsoCode = setLang || userLang; self.defaultLanguageIsoCode = setLang || userLang;
self.defaultLanguageName = lodash.result(lodash.find(self.availableLanguages, { 'isoCode': self.defaultLanguageIsoCode }), 'name'); self.defaultLanguageName = lodash.result(lodash.find(self.availableLanguages, {
'isoCode': self.defaultLanguageIsoCode
}), 'name');
}; };
// UX event handlers // UX event handlers
@ -607,6 +639,10 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.updateTxHistory(); self.updateTxHistory();
}); });
$rootScope.$on('Local/SetTab', function(event, tab) {
self.setTab(tab);
});
$rootScope.$on('Local/NeedsPassword', function(event, isSetup, cb) { $rootScope.$on('Local/NeedsPassword', function(event, isSetup, cb) {
self.askPassword = { self.askPassword = {
isSetup: isSetup, isSetup: isSetup,

View file

@ -1,63 +1,68 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('paymentUriController', angular.module('copayApp.controllers').controller('paymentUriController',
function($rootScope, $stateParams, $location, $timeout, profileService, configService, lodash, bitcore, go) { function($rootScope, $stateParams, $location, $timeout, profileService, configService, lodash, bitcore, go) {
function strip(number) { function strip(number) {
return (parseFloat(number.toPrecision(12))); return (parseFloat(number.toPrecision(12)));
}; };
// Build bitcoinURI with querystring // Build bitcoinURI with querystring
this.checkBitcoinUri = function() { this.checkBitcoinUri = function() {
var query = []; var query = [];
angular.forEach($location.search(), function(value, key) { angular.forEach($location.search(), function(value, key) {
query.push(key + "=" + value); query.push(key + "=" + value);
}); });
var queryString = query ? query.join("&") : null; var queryString = query ? query.join("&") : null;
this.bitcoinURI = $stateParams.data + ( queryString ? '?' + queryString : ''); this.bitcoinURI = $stateParams.data + (queryString ? '?' + queryString : '');
var URI = bitcore.URI; var URI = bitcore.URI;
var isUriValid = URI.isValid(this.bitcoinURI); var isUriValid = URI.isValid(this.bitcoinURI);
if (!URI.isValid(this.bitcoinURI)) { if (!URI.isValid(this.bitcoinURI)) {
this.error = true; this.error = true;
return; return;
} }
var uri = new URI(this.bitcoinURI); var uri = new URI(this.bitcoinURI);
if (uri && uri.address) { if (uri && uri.address) {
var config = configService.getSync().wallet.settings; var config = configService.getSync().wallet.settings;
var unitToSatoshi = config.unitToSatoshi; var unitToSatoshi = config.unitToSatoshi;
var satToUnit = 1 / unitToSatoshi; var satToUnit = 1 / unitToSatoshi;
var unitName = config.unitName; var unitName = config.unitName;
uri.amount = strip(uri.amount * satToUnit) + ' ' + unitName; uri.amount = strip(uri.amount * satToUnit) + ' ' + unitName;
return uri; uri.network = uri.address.network.name;
} return uri;
}; }
};
this.getWallets = function() { this.getWallets = function(network) {
if (!profileService.profile) return; if (!profileService.profile) return;
var config = configService.getSync(); var config = configService.getSync();
config.colorFor = config.colorFor || {}; config.colorFor = config.colorFor || {};
var ret = lodash.map(profileService.profile.credentials, function(c) { var ret = lodash.map(profileService.profile.credentials, function(c) {
return { return {
m: c.m, m: c.m,
n: c.n, n: c.n,
name: c.walletName, name: c.walletName,
id: c.walletId, id: c.walletId,
color: config.colorFor[c.walletId] || '#2C3E50' network: c.network,
}; color: config.colorFor[c.walletId] || '#2C3E50'
}); };
return lodash.sortBy(ret, 'walletName'); });
}; ret = lodash.filter(ret, function(w) {
return (w.network == network);
});
return lodash.sortBy(ret, 'walletName');
};
this.selectWallet = function(wid) { this.selectWallet = function(wid) {
var self = this; var self = this;
if (wid != profileService.focusedClient.credentials.walletId) { if (wid != profileService.focusedClient.credentials.walletId) {
profileService.setAndStoreFocus(wid, function() {}); profileService.setAndStoreFocus(wid, function() {});
} }
go.send(); go.send();
$timeout(function() { $timeout(function() {
$rootScope.$emit('paymentUri', self.bitcoinURI); $rootScope.$emit('paymentUri', self.bitcoinURI);
}, 100); }, 100);
}; };
}); });

View file

@ -3,8 +3,6 @@
angular.module('copayApp.controllers').controller('receiveController', angular.module('copayApp.controllers').controller('receiveController',
function($rootScope, $scope, $timeout, $modal, $log, isCordova, isMobile, profileService, storageService) { function($rootScope, $scope, $timeout, $modal, $log, isCordova, isMobile, profileService, storageService) {
var self = this; var self = this;
var fc = profileService.focusedClient;
this.isCordova = isCordova; this.isCordova = isCordova;
self.addresses = []; self.addresses = [];
@ -15,6 +13,7 @@ angular.module('copayApp.controllers').controller('receiveController',
$scope.$on('$destroy', newAddrListener); $scope.$on('$destroy', newAddrListener);
this.newAddress = function() { this.newAddress = function() {
var fc = profileService.focusedClient;
self.generatingAddress = true; self.generatingAddress = true;
self.error = null; self.error = null;
fc.createAddress(function(err, addr) { fc.createAddress(function(err, addr) {
@ -32,6 +31,7 @@ angular.module('copayApp.controllers').controller('receiveController',
}; };
this.getAddress = function() { this.getAddress = function() {
var fc = profileService.focusedClient;
$timeout(function() { $timeout(function() {
storageService.getLastAddress(fc.credentials.walletId, function(err, addr) { storageService.getLastAddress(fc.credentials.walletId, function(err, addr) {
if (addr) { if (addr) {

View file

@ -21,7 +21,7 @@ angular.module('copayApp.controllers').controller('topbarController', function($
}, 100); }, 100);
alert('Scanning error'); alert('Scanning error');
}); });
go.send(); go.send();
}; };
var modalOpenScanner = function() { var modalOpenScanner = function() {

View file

@ -1,8 +1,72 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $rootScope, $timeout, $filter, $modal, notification, txStatus, isCordova, profileService, lodash) { angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $rootScope, $timeout, $filter, $modal, $log, notification, txStatus, isCordova, profileService, lodash, configService, rateService, storageService, bitcore, isChromeApp) {
var self = this;
$rootScope.hideMenuBar = false; $rootScope.hideMenuBar = false;
$rootScope.wpInputFocused = false;
// INIT
var config = configService.getSync().wallet.settings;
this.unitToSatoshi = config.unitToSatoshi;
this.satToUnit = 1 / this.unitToSatoshi;
this.unitName = config.unitName;
this.alternativeIsoCode = config.alternativeIsoCode;
this.alternativeName = config.alternativeName;
this.alternativeAmount = 0;
this.unitDecimals = config.unitDecimals;
this.isCordova = isCordova;
this.addresses = [];
this.isMobile = isMobile.any();
this.isWindowsPhoneApp = isMobile.Windows() && isCordova;
this.blockUx = false;
this.isRateAvailable = false;
this.showScanner = false;
this.isMobile = isMobile.any();
var disableScannerListener = $rootScope.$on('dataScanned', function(event, data) {
$scope.$emit('Local/SetTab', 'send');
self.setForm(data);
});
var disablePaymentUriListener = $rootScope.$on('paymentUri', function(event, uri) {
$timeout(function() {
$scope.$emit('Local/SetTab', 'send');
self.setForm(uri);
}, 100);
});
var disableAddrListener = $rootScope.$on('Local/NeedNewAddress', function() {
self.getAddress();
});
var disableTabListener = $rootScope.$on('Local/TabChanged', function(e,tab){
switch(tab) {
case 'send':
self.resetError();
self.setInputs();
case 'receive':
self.getAddress();
break;
};
});
$scope.$on('$destroy', function() {
disableAddrListener();
disableScannerListener();
disablePaymentUriListener();
disableTabListener();
$rootScope.hideMenuBar = false;
});
rateService.whenAvailable(function() {
self.isRateAvailable = true;
$rootScope.$digest();
});
// walletHome
$scope.openCopayersModal = function(copayers, copayerId) { $scope.openCopayersModal = function(copayers, copayerId) {
var fc = profileService.focusedClient; var fc = profileService.focusedClient;
@ -21,8 +85,6 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
}); });
}; };
$scope.openTxModal = function(tx, copayers) { $scope.openTxModal = function(tx, copayers) {
var fc = profileService.focusedClient; var fc = profileService.focusedClient;
var ModalInstanceCtrl = function($scope, $modalInstance) { var ModalInstanceCtrl = function($scope, $modalInstance) {
@ -213,4 +275,507 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
}; };
// Receive
this.newAddress = function() {
var fc = profileService.focusedClient;
self.generatingAddress = true;
self.error = null;
fc.createAddress(function(err, addr) {
self.generatingAddress = false;
if (err) {
$log.debug('Creating address ERROR:', err);
$scope.$emit('Local/ClientError', err);
self.error = 'Could not generate address';
} else {
self.addr = addr.address;
storageService.storeLastAddress(fc.credentials.walletId, addr.address, function() {});
}
$scope.$digest();
});
};
this.getAddress = function() {
var fc = profileService.focusedClient;
$timeout(function() {
storageService.getLastAddress(fc.credentials.walletId, function(err, addr) {
if (addr) {
self.addr = addr;
} else {
self.newAddress();
}
});
});
};
this.copyAddress = function(addr) {
if (isCordova) {
window.cordova.plugins.clipboard.copy('bitcoin:' + addr);
window.plugins.toast.showShortCenter('Copied to clipboard');
}
};
this.shareAddress = function(addr) {
if (isCordova) {
if (isMobile.Android() || isMobile.Windows()) {
window.ignoreMobilePause = true;
}
window.plugins.socialsharing.share('bitcoin:' + addr, null, null, null);
}
};
// Send
this.resetError = function() {
this.error = this.success = null;
};
var hideMenuBar = lodash.debounce(function(hide) {
if (hide) {
$rootScope.hideMenuBar = true;
} else {
$rootScope.hideMenuBar = false;
}
$rootScope.$digest();
}, 100);
this.formFocus = function(what) {
if (isCordova) {
hideMenuBar(what);
}
if (!this.isWindowsPhoneApp) return
if (!what) {
this.hideAddress = false;
this.hideAmount = false;
} else {
if (what == 'amount') {
this.hideAddress = true;
} else if (what == 'msg') {
this.hideAddress = true;
this.hideAmount = true;
}
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
this.setInputs = function() {
var unitToSat = this.unitToSatoshi;
var satToUnit = 1 / unitToSat;
/**
* Setting the two related amounts as properties prevents an infinite
* recursion for watches while preserving the original angular updates
*
*/
Object.defineProperty($scope,
"_alternative", {
get: function() {
return $scope.__alternative;
},
set: function(newValue) {
$scope.__alternative = newValue;
if (typeof(newValue) === 'number' && self.isRateAvailable) {
$scope._amount = parseFloat((rateService.fromFiat(newValue, self.alternativeIsoCode) * satToUnit).toFixed(self.unitDecimals), 10);
}
},
enumerable: true,
configurable: true
});
Object.defineProperty($scope,
"_amount", {
get: function() {
return $scope.__amount;
},
set: function(newValue) {
$scope.__amount = newValue;
if (typeof(newValue) === 'number' && self.isRateAvailable) {
$scope.__alternative = parseFloat((rateService.toFiat(newValue * self.unitToSatoshi, self.alternativeIsoCode)).toFixed(2), 10);
} else {
$scope.__alternative = 0;
}
self.alternativeAmount = $scope.__alternative;
self.resetError();
},
enumerable: true,
configurable: true
});
Object.defineProperty($scope,
"_address", {
get: function() {
return $scope.__address;
},
set: function(newValue) {
$scope.__address = self.onAddressChange(newValue);
},
enumerable: true,
configurable: true
});
};
this.setError = function(err) {
var fc = profileService.focusedClient;
$log.warn(err);
var errMessage = 'The transaction' + (fc.credentials.m > 1 ? ' proposal' : '') +
' could not be created: ' + (err.message ? err.message : err);
this.error = errMessage;
$timeout(function() {
$scope.$digest();
}, 1);
};
this.setOngoingProcess = function(name) {
var self = this;
$timeout(function() {
self.onGoingProcess = name;
$rootScope.$apply();
})
};
this.submitForm = function(form) {
var fc = profileService.focusedClient;
var unitToSat = this.unitToSatoshi;
if (form.$invalid) {
this.error = 'Unable to send transaction proposal';
return;
}
if (fc.isPrivKeyEncrypted()) {
profileService.unlockFC(function(err) {
if (err) return self.setError(err);
return self.submitForm(form);
});
return;
};
self.blockUx = true;
self.setOngoingProcess('Sending');
if (isCordova) {
window.plugins.spinnerDialog.show(null, 'Creating transaction...', true);
}
$timeout(function() {
var comment = form.comment.$modelValue;
var paypro = self._paypro;
var address, amount;
address = form.address.$modelValue;
amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0));
fc.sendTxProposal({
toAddress: address,
amount: amount,
message: comment,
payProUrl: paypro ? paypro.url : null,
}, function(err, txp) {
self.setOngoingProcess();
if (err) {
profileService.lockFC();
if (isCordova) {
window.plugins.spinnerDialog.hide();
}
self.blockUx = false;
return self.setError(err);
}
self.signAndBroadcast(txp, function(err) {
self.setOngoingProcess();
if (isCordova) {
window.plugins.spinnerDialog.hide();
}
self.blockUx = false;
if (err) {
profileService.lockFC();
return self.setError(err);
}
self.resetForm(form);
});
});
}, 100);
};
this.signAndBroadcast = function(txp, cb) {
var fc = profileService.focusedClient;
self.setOngoingProcess('Signing');
fc.signTxProposal(txp, function(err, signedTx) {
profileService.lockFC();
self.setOngoingProcess();
if (err) return cb(err);
if (signedTx.status == 'accepted') {
self.setOngoingProcess('Broadcasting');
fc.broadcastTxProposal(signedTx, function(err, btx) {
self.setOngoingProcess();
if (err) {
$scope.error = 'Transaction not broadcasted. Please try again.';
$scope.$digest();
} else {
txStatus.notify(btx);
$scope.$emit('Local/TxProposalAction');
}
return cb();
});
} else {
txStatus.notify(signedTx);
$scope.$emit('Local/TxProposalAction');
return cb();
}
});
};
this.setTopAmount = function() {
throw new Error('todo: setTopAmount');
var form = $scope.sendForm;
if (form) {
form.amount.$setViewValue(w.balanceInfo.topAmount);
form.amount.$render();
form.amount.$isValid = true;
}
};
this.setForm = function(to, amount, comment) {
var form = $scope.sendForm;
if (to) {
form.address.$setViewValue(to);
form.address.$isValid = true;
form.address.$render();
this.lockAddress = true;
}
if (amount) {
form.amount.$setViewValue("" + amount);
form.amount.$isValid = true;
form.amount.$render();
this.lockAmount = true;
}
if (comment) {
form.comment.$setViewValue(comment);
form.comment.$isValid = true;
form.comment.$render();
}
};
this.resetForm = function(form) {
this.resetError();
this.fetchingURL = null;
this._paypro = null;
this.lockAddress = false;
this.lockAmount = false;
this._amount = this._address = null;
if (form && form.amount) {
form.amount.$pristine = true;
form.amount.$setViewValue('');
form.amount.$render();
form.comment.$setViewValue('');
form.comment.$render();
form.$setPristine();
if (form.address) {
form.address.$pristine = true;
form.address.$setViewValue('');
form.address.$render();
}
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
this.openPPModal = function(paypro) {
var ModalInstanceCtrl = function($scope, $modalInstance) {
var fc = profileService.focusedClient;
var satToUnit = 1 / self.unitToSatoshi;
$scope.paypro = paypro;
$scope.alternative = self.alternativeAmount;
$scope.alternativeIsoCode = self.alternativeIsoCode;
$scope.isRateAvailable = self.isRateAvailable;
$scope.unitTotal = (paypro.amount * satToUnit).toFixed(self.unitDecimals);
$scope.unitName = self.unitName;
$scope.color = fc.backgroundColor;
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
$modal.open({
templateUrl: 'views/modals/paypro.html',
windowClass: 'full',
controller: ModalInstanceCtrl,
});
};
this.setFromPayPro = function(uri, form) {
var fc = profileService.focusedClient;
if (isChromeApp) {
this.error = 'Payment Protocol not supported on Chrome App';
return;
}
var satToUnit = 1 / this.unitToSatoshi;
this.fetchingURL = uri;
this.blockUx = true;
var self = this;
$log.debug('Fetch PayPro Request...', uri);
$timeout(function() {
fc.fetchPayPro({
payProUrl: uri,
}, function(err, paypro) {
$log.debug(paypro);
self.blockUx = false;
self.fetchingURL = null;
if (err) {
$log.warn(err);
self.resetForm(form);
var msg = err.toString();
if (msg.match('HTTP')) {
msg = 'Could not fetch payment information';
}
self.error = msg;
} else {
self._paypro = paypro;
self.setForm(paypro.toAddress, (paypro.amount * satToUnit).toFixed(self.unitDecimals),
paypro.memo);
}
});
}, 1);
};
this.setFromUri = function(uri) {
function sanitizeUri(uri) {
// Fixes when a region uses comma to separate decimals
var regex = /[\?\&]amount=(\d+([\,\.]\d+)?)/i;
var match = regex.exec(uri);
if (!match || match.length === 0) {
return uri;
}
var value = match[0].replace(',', '.');
var newUri = uri.replace(regex, value);
return newUri;
};
var satToUnit = 1 / this.unitToSatoshi;
uri = sanitizeUri(uri);
if (!bitcore.URI.isValid(uri)) {
return uri;
}
var parsed = new bitcore.URI(uri);
var addr = parsed.address.toString();
var message = parsed.message;
if (parsed.r)
return this.setFromPayPro(parsed.r);
var amount = parsed.amount ?
(parsed.amount.toFixed(0) * satToUnit).toFixed(this.unitDecimals) : 0;
this.setForm(addr, amount, message);
return addr;
};
this.onAddressChange = function(value) {
this.resetError();
if (!value) return '';
if (this._paypro)
return value;
if (value.indexOf('bitcoin:') === 0) {
return this.setFromUri(value);
} else if (/^https?:\/\//.test(value)) {
return this.setFromPayPro(value);
} else {
return value;
}
};
// History
function strip(number) {
return (parseFloat(number.toPrecision(12)));
}
this.getUnitName = function() {
return this.unitName;
};
this.getAlternativeIsoCode = function() {
return this.alternativeIsoCode;
};
this._addRates = function(txs, cb) {
if (!txs || txs.length == 0) return cb();
var index = lodash.groupBy(txs, 'rateTs');
rateService.getHistoricRates(config.alternativeIsoCode, lodash.keys(index), function(err, res) {
if (err || !res) return cb(err);
lodash.each(res, function(r) {
lodash.each(index[r.ts], function(tx) {
var alternativeAmount = (r.rate != null ? tx.amount * rateService.SAT_TO_BTC * r.rate : null);
tx.alternativeAmount = alternativeAmount ? $filter('noFractionNumber')(alternativeAmount, 2) : null;
});
});
return cb();
});
};
this.openTxModal = function(btx) {
var self = this;
var fc = profileService.focusedClient;
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.btx = btx;
$scope.settings = config;
$scope.color = fc.backgroundColor;
$scope.getAmount = function(amount) {
return self.getAmount(amount);
};
$scope.getUnitName = function() {
return self.getUnitName();
};
$scope.getShortNetworkName = function() {
var n = fc.credentials.network;
return n.substring(0, 4);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
$modal.open({
templateUrl: 'views/modals/tx-details.html',
windowClass: 'full',
controller: ModalInstanceCtrl,
});
};
this.hasAction = function(actions, action) {
return actions.hasOwnProperty('create');
};
}); });

View file

@ -179,63 +179,6 @@ angular
templateUrl: 'views/profile.html', templateUrl: 'views/profile.html',
needProfile: true needProfile: true
}) })
.state('receive', {
url: '/receive',
walletShouldBeComplete: true,
needProfile: true,
views: {
'main': {
templateUrl: 'views/receive.html'
},
'topbar': {
templateUrl: 'views/includes/topbar.html'
},
'menu': {
templateUrl: 'views/includes/menu.html',
controller: function($scope) {
$scope.activeMenu = 'receive';
}
}
}
})
.state('send', {
url: '/send',
walletShouldBeComplete: true,
needProfile: true,
views: {
'main': {
templateUrl: 'views/send.html'
},
'topbar': {
templateUrl: 'views/includes/topbar.html'
},
'menu': {
templateUrl: 'views/includes/menu.html',
controller: function($scope) {
$scope.activeMenu = 'send';
}
}
}
})
.state('history', {
url: '/history',
walletShouldBeComplete: true,
needProfile: true,
views: {
'main': {
templateUrl: 'views/history.html'
},
'topbar': {
templateUrl: 'views/includes/topbar.html'
},
'menu': {
templateUrl: 'views/includes/menu.html',
controller: function($scope) {
$scope.activeMenu = 'history';
}
}
}
})
.state('preferences', { .state('preferences', {
url: '/preferences', url: '/preferences',
templateUrl: 'views/preferences.html', templateUrl: 'views/preferences.html',

View file

@ -36,8 +36,11 @@ angular.module('copayApp.services').factory('go', function($window, $rootScope,
var ref = window.open(url, '_blank', 'location=no'); var ref = window.open(url, '_blank', 'location=no');
}; };
root.path = function(path) { root.path = function(path, cb) {
$state.transitionTo(path); $state.transitionTo(path)
.then(function() {
if (cb) return cb();
});
hideSidebars(); hideSidebars();
}; };
@ -51,10 +54,19 @@ angular.module('copayApp.services').factory('go', function($window, $rootScope,
if (fc && !fc.isComplete()) { if (fc && !fc.isComplete()) {
root.path('copayers'); root.path('copayers');
} else { } else {
root.path('walletHome'); root.path('walletHome', function() {
$rootScope.$emit('Local/SetTab', 'walletHome');
});
} }
}; };
root.send = function() {
root.path('walletHome', function() {
$rootScope.$emit('Local/SetTab', 'send');
});
};
root.home = function() { root.home = function() {
if ($rootScope.iden) if ($rootScope.iden)
root.walletHome(); root.walletHome();
@ -66,10 +78,6 @@ angular.module('copayApp.services').factory('go', function($window, $rootScope,
$state.go('add'); $state.go('add');
}; };
root.send = function() {
$state.go('send');
};
root.preferences = function() { root.preferences = function() {
$state.go('preferences'); $state.go('preferences');
}; };