Merge remote-tracking branch 'origin/wallet/task/440' into wallet/task/514

# Conflicts:
#	i18n/po/template.pot
#	src/js/controllers/amount.js
#	www/css/main.css
This commit is contained in:
Sebastiaan Pasma 2018-08-02 15:12:40 +02:00
commit 391201471d
No known key found for this signature in database
GPG key ID: 9A2B0C8B95A1D26F
22 changed files with 702 additions and 47 deletions

View file

@ -3714,4 +3714,33 @@ msgstr ""
#: src/js/controllers/amount.js:49 #: src/js/controllers/amount.js:49
msgid "Address doesn\'t contain currency information, please make sure you are sending the correct currency." msgid "Address doesn\'t contain currency information, please make sure you are sending the correct currency."
msgstr ""
#: www/views/review.html:4
msgid "Review Transaction"
msgstr ""
#: www/views/review.html:14
msgid "You are sending"
msgstr ""
#: www/views/review.html:22
msgid "From:"
msgstr ""
#: www/views/review.html:36
msgid "To:"
msgstr ""
#: www/views/review.html:53
msgid "Add personal note"
msgstr ""
#: www/views/review.html:57
msgid "Personal note:"
msgstr ""
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "" msgstr ""

View file

@ -35,9 +35,9 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
vm.save = save; vm.save = save;
vm.sendMax = sendMax; vm.sendMax = sendMax;
vm.errorMessage = ''; vm.errorMessage = '';
$scope.$on('$ionicView.beforeEnter', onBeforeEnter); $scope.$on('$ionicView.beforeEnter', onBeforeEnter);
$scope.$on('$ionicView.leave', onLeave); $scope.$on('$ionicView.leave', onLeave);
var LENGTH_EXPRESSION_LIMIT = 19; var LENGTH_EXPRESSION_LIMIT = 19;
var LENGTH_BEFORE_COMMA_EXPRESSION_LIMIT = 8; var LENGTH_BEFORE_COMMA_EXPRESSION_LIMIT = 8;
@ -66,7 +66,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
} }
function onBeforeEnter(event, data) { function onBeforeEnter(event, data) {
initCurrencies(); initCurrencies();
passthroughParams = data.stateParams; passthroughParams = data.stateParams;
@ -81,7 +81,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
setAvailableUnits(); setAvailableUnits();
updateUnitUI(); updateUnitUI();
var reNr = /^[1234567890\.]$/; var reNr = /^[1234567890\.]$/;
var reOp = /^[\*\+\-\/]$/; var reOp = /^[\*\+\-\/]$/;
@ -153,7 +153,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
unitIndex = 0; unitIndex = 0;
// currency have preference // currency have preference
var fiatName; var fiatName;
if (data.stateParams.currency) { if (data.stateParams.currency) {
@ -260,11 +260,11 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
if (vm.amount == '0' && digit == '0') return; if (vm.amount == '0' && digit == '0') return;
if (availableUnits[unitIndex].isFiat && vm.amount.indexOf('.') > -1 && vm.amount[vm.amount.indexOf('.') + 2]) return; if (availableUnits[unitIndex].isFiat && vm.amount.indexOf('.') > -1 && vm.amount[vm.amount.indexOf('.') + 2]) return;
if (vm.amount == '0' && digit != '.') { if (vm.amount == '0' && digit != '.') {
vm.amount = ''; vm.amount = '';
} }
if (vm.amount == '' && digit == '.') { if (vm.amount == '' && digit == '.') {
vm.amount = '0'; vm.amount = '0';
} }
@ -335,16 +335,16 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
if (a) { if (a) {
amountInCrypto = a; amountInCrypto = a;
var amountInSatoshis = a * unitToSatoshi; var amountInSatoshis = a * unitToSatoshi;
vm.fundsAreInsufficient = !!passthroughParams.fromWalletId vm.fundsAreInsufficient = !!passthroughParams.fromWalletId
&& availableSatoshis !== null && availableSatoshis !== null
&& availableSatoshis < amountInSatoshis; && availableSatoshis < amountInSatoshis;
vm.alternativeAmount = txFormatService.formatAmount(amountInSatoshis, true); vm.alternativeAmount = txFormatService.formatAmount(amountInSatoshis, true);
vm.allowSend = lodash.isNumber(a) vm.allowSend = lodash.isNumber(a)
&& a > 0 && a > 0
&& (!vm.shapeshiftOrderId && (!vm.shapeshiftOrderId
|| (a >= vm.minAmount && a <= vm.maxAmount)) || (a >= vm.minAmount && a <= vm.maxAmount))
&& !vm.fundsAreInsufficient; && !vm.fundsAreInsufficient;
} else { } else {
if (result) { if (result) {
vm.alternativeAmount = 'N/A'; vm.alternativeAmount = 'N/A';
@ -356,16 +356,16 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
} }
} else { } else {
amountInCrypto = result; amountInCrypto = result;
vm.fundsAreInsufficient = passthroughParams.fromWalletId vm.fundsAreInsufficient = passthroughParams.fromWalletId
&& availableSatoshis !== null && availableSatoshis !== null
&& availableSatoshis < result * unitToSatoshi; && availableSatoshis < result * unitToSatoshi;
vm.alternativeAmount = $filter('formatFiatAmount')(toFiat(result)); vm.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
vm.allowSend = lodash.isNumber(result) vm.allowSend = lodash.isNumber(result)
&& result > 0 && result > 0
&& (!vm.shapeshiftOrderId && (!vm.shapeshiftOrderId
|| (result >= vm.minAmount && result <= vm.maxAmount)) || (result >= vm.minAmount && result <= vm.maxAmount))
&& !vm.fundsAreInsufficient; && !vm.fundsAreInsufficient;
} }
} else { } else {
@ -381,7 +381,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
} else if (amountInCrypto > vm.maxAmount) { } else if (amountInCrypto > vm.maxAmount) {
vm.errorMessage = gettextCatalog.getString('Amount is above maximum'); vm.errorMessage = gettextCatalog.getString('Amount is above maximum');
} else { } else {
vm.errorMessage = ''; vm.errorMessage = '';
} }
@ -474,7 +474,9 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
} }
} }
$state.transitionTo('tabs.send.confirm', confirmData); $state.transitionTo('tabs.send.review', confirmData);
}
$scope.useSendMax = null;
} }
}; };
@ -585,7 +587,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
close(); close();
}); });
}; };
function updateAvailableFundsStringIfNeeded() { function updateAvailableFundsStringIfNeeded() {
if (passthroughParams.fromWalletId && availableSatoshis !== null) { if (passthroughParams.fromWalletId && availableSatoshis !== null) {
availableFundsInFiat = ''; availableFundsInFiat = '';

View file

@ -0,0 +1,214 @@
'use strict';
angular
.module('copayApp.controllers')
.controller('reviewController', reviewController);
function reviewController(addressbookService, configService, profileService, $log, $scope, txFormatService) {
var vm = this;
vm.destination = {
address: '',
balanceAmount: '',
balanceCurrency: '',
coin: '',
color: '',
currency: '',
currencyColor: '',
kind: '', // 'address', 'contact', 'wallet'
name: ''
};
vm.feeCrypto = '';
vm.feeFiat = '';
vm.origin = {
balanceAmount: '',
balanceCurrency: '',
color: '',
currency: '',
currencyColor: '',
name: '',
};
vm.primaryAmount = '';
vm.primaryCurrency = '';
vm.secondaryAmount = '';
vm.secondaryCurrency = '';
var config = null;
var coin = '';
var originWalletId = '';
var priceDisplayIsFiat = true;
var satoshis = null;
var toAddress = '';
var destinationWalletId = '';
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
function onBeforeEnter(event, data) {
originWalletId = data.stateParams.fromWalletId;
satoshis = parseInt(data.stateParams.amount, 10);
toAddress = data.stateParams.toAddr;
var originWallet = profileService.getWallet(originWalletId);
vm.origin.currency = originWallet.coin.toUpperCase();
vm.origin.color = originWallet.color;
vm.origin.name = originWallet.name;
coin = originWallet.coin;
configService.get(function onConfig(err, configCache) {
if (err) {
$log.err('Error getting config.', err);
} else {
config = configCache;
priceDisplayIsFiat = config.wallet.settings.priceDisplay === 'fiat';
vm.origin.currencyColor = originWallet.coin === 'btc' ? config.bitcoinWalletColor : config.bitcoinCashWalletColor;
}
updateSendAmounts();
getOriginWalletBalance(originWallet);
handleDestinationAsAddress(toAddress, coin);
handleDestinationAsWallet(data.stateParams.toWalletId);
});
}
function getOriginWalletBalance(originWallet) {
var balanceText = getWalletBalanceDisplayText(originWallet);
vm.origin.balanceAmount = balanceText.amount;
vm.origin.balanceCurrency = balanceText.currency;
}
function getWalletBalanceDisplayText(wallet) {
var balanceCryptoAmount = '';
var balanceCryptoCurrencyCode = '';
var balanceFiatAmount = '';
var balanceFiatCurrency = ''
var displayAmount = '';
var displayCurrency = '';
var walletStatus = null;
if (wallet.status.isValid) {
walletStatus = wallet.status;
} else if (wallet.cachedStatus.isValid) {
walletStatus = wallet.cachedStatus;
}
if (walletStatus) {
var cryptoBalanceParts = walletStatus.spendableBalanceStr.split(' ');
balanceCryptoAmount = cryptoBalanceParts[0];
balanceCryptoCurrencyCode = cryptoBalanceParts.length > 1 ? cryptoBalanceParts[1] : '';
if (walletStatus.alternativeBalanceAvailable) {
balanceFiatAmount = walletStatus.spendableBalanceAlternative;
balanceFiatCurrency = walletStatus.alternativeIsoCode;
}
}
if (priceDisplayIsFiat) {
displayAmount = balanceFiatAmount ? balanceFiatAmount : balanceCryptoAmount;
displayCurrency = balanceFiatAmount ? balanceFiatCurrency : balanceCryptoCurrencyCode;
} else {
displayAmount = balanceCryptoAmount;
displayCurrency = balanceCryptoCurrencyCode;
}
return {
amount: displayAmount,
currency: displayCurrency
};
}
function handleDestinationAsAddress(address, originCoin) {
if (!address) {
return;
}
// Check if the recipient is a contact
addressbookService.get(originCoin + address, function(err, contact) {
if (!err && contact) {
console.log('destination is contact');
handleDestinationAsContact(contact);
} else {
console.log('destination is address');
vm.destination.address = address;
vm.destination.kind = 'address';
}
});
}
function handleDestinationAsContact(contact) {
vm.destination.kind = 'contact';
vm.destination.name = contact.name;
vm.destination.color = contact.coin === 'btc' ? config.bitcoinWalletColor : config.bitcoinCashWalletColor;
vm.destination.currency = contact.coin.toUpperCase();
vm.destination.currencyColor = vm.destination.color;
}
function handleDestinationAsWallet(walletId) {
destinationWalletId = walletId;
if (!destinationWalletId) {
return;
}
console.log('destination is wallet');
var destinationWallet = profileService.getWallet(destinationWalletId);
vm.destination.coin = destinationWallet.coin;
vm.destination.color = destinationWallet.color;
vm.destination.currency = destinationWallet.coin.toUpperCase();
vm.destination.kind = 'wallet';
vm.destination.name = destinationWallet.name;
if (config) {
vm.destination.currencyColor = vm.destination.coin === 'btc' ? config.bitcoinWalletColor : config.bitcoinCashWalletColor;
}
var balanceText = getWalletBalanceDisplayText(destinationWallet);
vm.destination.balanceAmount = balanceText.amount;
vm.destination.balanceCurrency = balanceText.currency;
}
function updateSendAmounts() {
if (typeof satoshis !== 'number') {
return;
}
var cryptoAmount = '';
var cryptoCurrencyCode = '';
var amountStr = txFormatService.formatAmountStr(coin, satoshis);
if (amountStr) {
var amountParts = amountStr.split(' ');
cryptoAmount = amountParts[0];
cryptoCurrencyCode = amountParts.length > 1 ? amountParts[1] : '';
}
// Want to avoid flashing of amount strings so do all formatting after this has returned.
txFormatService.formatAlternativeStr(coin, satoshis, function(v) {
if (!v) {
vm.primaryAmount = cryptoAmount;
vm.primaryCurrency = cryptoCurrencyCode;
vm.secondaryAmount = '';
vm.secondaryCurrency = '';
return;
}
vm.secondaryAmount = vm.primaryAmount;
vm.secondaryCurrency = vm.primaryCurrency;
var fiatParts = v.split(' ');
var fiatAmount = fiatParts[0];
var fiatCurrency = fiatParts.length > 1 ? fiatParts[1] : '';
if (priceDisplayIsFiat) {
vm.primaryAmount = fiatAmount;
vm.primaryCurrency = fiatCurrency;
vm.secondaryAmount = cryptoAmount;
vm.secondaryCurrency = cryptoCurrencyCode;
} else {
vm.primaryAmount = cryptoAmount;
vm.primaryCurrency = cryptoCurrencyCode;
vm.secondaryAmount = fiatAmount;
vm.secondaryCurrency = fiatCurrency;
}
});
}
}

View file

@ -48,37 +48,44 @@ angular.module('bitcoincom.directives')
return '2'; return '2';
}; };
switch (getDecimalPlaces($scope.currency)) { var formatNumbers = function(currency, value) {
case '0': switch (getDecimalPlaces(currency)) {
var valueFormatted = numberWithCommas(Math.round(parseFloat($scope.value))); case '0':
buildAmount(valueFormatted, '', ''); var valueFormatted = numberWithCommas(Math.round(parseFloat(value)));
break;
case '2':
var valueProcessing = parseFloat(parseFloat($scope.value).toFixed(2));
var valueFormatted = numberWithCommas(valueProcessing);
buildAmount(valueFormatted, '', '');
break;
case '3':
var valueProcessing = parseFloat(parseFloat($scope.value).toFixed(3));
var valueFormatted = numberWithCommas(valueProcessing);
buildAmount(valueFormatted, '', '');
break;
case '8':
var valueFormatted = parseFloat($scope.value).toFixed(8);
if (parseFloat($scope.value) == 0) {
buildAmount('0', '', '');
} else {
buildAmount(valueFormatted, '', ''); buildAmount(valueFormatted, '', '');
var start = numberWithCommas(valueFormatted.slice(0, -5)); break;
var middle = valueFormatted.slice(-5, -2);
var end = valueFormatted.substr(valueFormatted.length - 2); case '2':
buildAmount(start, middle, end); var valueProcessing = parseFloat(parseFloat(value).toFixed(2));
} var valueFormatted = numberWithCommas(valueProcessing);
break; buildAmount(valueFormatted, '', '');
break;
case '3':
var valueProcessing = parseFloat(parseFloat(value).toFixed(3));
var valueFormatted = numberWithCommas(valueProcessing);
buildAmount(valueFormatted, '', '');
break;
case '8':
var valueFormatted = parseFloat(value).toFixed(8);
if (parseFloat(value) == 0) {
buildAmount('0', '', '');
} else {
buildAmount(valueFormatted, '', '');
var start = numberWithCommas(valueFormatted.slice(0, -5));
var middle = valueFormatted.slice(-5, -2);
var end = valueFormatted.substr(valueFormatted.length - 2);
buildAmount(start, middle, end);
}
break;
}
} }
formatNumbers($scope.currency, $scope.value);
$scope.$watchGroup(['currency', 'value'], function() {
formatNumbers($scope.currency, $scope.value);
});
}] }]
}; };
} }

View file

@ -344,6 +344,19 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
} }
} }
}) })
.state('tabs.send.review', {
url: '/review/:amount/:fromWalletId/:sendMax/:toAddr/:toWalletId',
views: {
'tab-send@tabs': {
controller: 'reviewController',
controllerAs: 'vm',
templateUrl: 'views/review.html'
}
},
params: {
paypro: null
}
})
/* /*
* *

View file

@ -0,0 +1,24 @@
.action-minor {
margin: 20px 14px;
font-size: 14px;
&.mt-negative {
margin-top: 0;
}
&.text-right {
text-align: right;
}
> .action-icon {
width: 15px;
height: 15px;
vertical-align: middle;
margin-right: 3px;
}
> .action-text {
vertical-align: middle;
color: #444444;
}
}

View file

@ -0,0 +1,27 @@
.address {
background-color: #F8F8F8;
border: 0.5px solid #EDEBEB;
border-radius: 3px;
padding: 9px;
text-align: center;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
&.expanded {
white-space: pre-wrap;
word-break: break-all;
}
.prefix {
color: #000000;
}
.mid {
color: #919191;
}
.suffix {
color: #000000;
}
}

View file

@ -0,0 +1,5 @@
.card {
&.card-gutter-compact {
margin: 10px 12px;
}
}

View file

@ -1 +1,11 @@
@import "item";
@import "ion-content";
@import "card";
@import "header";
@import "content-frame";
@import "address";
@import "action-minor";
@import "expand-content";
@import "fee-summary";
@import "amount.scss"; @import "amount.scss";

View file

@ -0,0 +1,11 @@
.content-frame {
&.negative-top {
margin-top: -40px;
.card {
&:first-child {
margin-top: 0;
}
}
}
}

View file

@ -0,0 +1,26 @@
.expand-content-frame {
position: relative;
.expand-content-trigger {
position: absolute;
top: 0;
transition: opacity 0.3s ease;
right: 0;
&.expand-content-revealed {
opacity: 0;
}
}
.expand-content {
opacity: 0;
transform-origin: 100% 0%;
transform: scale(0,0);
transition: opacity 0.3s ease, transform 0.3s ease;
&.expand-content-revealed {
opacity: 1;
transform: scale(1,1);
}
}
}

View file

@ -0,0 +1,33 @@
.fee-summary {
position: relative;
display: flex;
justify-content: space-between;
width: 100%;
padding: 5px 12px 15px;
box-sizing: border-box;
background-color: #F2F2F2;
&:before {
content: '';
position: absolute;
left: 0;
top: -15px;
width: 100%;
height: 15px;
background: linear-gradient(to bottom, rgba(242,242,242,0) 0%,rgba(242,242,242,1) 100%);
}
.fee-fiat {
&.positive {
color: #70955F;
}
&.negative {
color: #C24633;
}
}
.fee-crypto {
color: #A7A7A7;
}
}

View file

@ -0,0 +1,36 @@
.header {
padding: 29px 12px 61px;
background-color: #FAB915;
color: #FFFFFF;
.title {
font-size: 18px;
font-weight: 400;
line-height: 1em;
color: #FFFFFF;
text-align: center;
+ .content {
margin-top: 23px;
}
}
.content {
text-align: center;
p {
margin: 0;
line-height: 1em;
font-size: 18px;
&.large {
font-size: 29px;
font-weight: 600;
}
+ p {
margin-top: 8px;
}
}
}
}

View file

@ -0,0 +1,17 @@
/*
* Extends Ionic v1 ion-content
*/
ion-content {
&.bg-neutral {
background-color: #F2F2F2;
}
&.padded-bottom-cta {
bottom: 92px;
}
&.padded-bottom-cta-with-summary {
bottom: 134px;
}
}

View file

@ -0,0 +1,48 @@
/*
* Extends Ionic v1 item
*/
.item {
&.item-compact {
padding: 11px 13px;
}
&.item-gutterless {
padding: 0;
}
.item-content {
&.item-content-avatar {
min-height: 69px;
padding: 13px 11px 13px 68px;
> img,
> i {
&:first-child {
position: absolute;
max-width: 40px;
max-height: 40px;
width: 100%;
height: 100%;
border-radius: 50%;
left: 13px;
top: 50%;
padding: 0;
transform: translate(0,-50%);
}
}
}
&.item-content-compact {
min-height: 0;
padding: 13px 11px;
}
.highlight {
color: #FAB915
}
+ .item-content {
padding-top: 0;
}
}
}

View file

@ -1 +1,2 @@
@import "gravatar"; @import "gravatar";
@import "elastic";

View file

@ -0,0 +1,4 @@
.elastic {
width: 100%;
font-size: 14px;
}

View file

@ -88,6 +88,13 @@
background-image: url('../img/icon-faucet.svg'); background-image: url('../img/icon-faucet.svg');
background-size: 70%; background-size: 70%;
} }
&.icon-wallet {
background-color: #FAB915;
background-image: url('../img/icon-wallet.svg');
border: none;
box-shadow: 0 0 0 1px rgba(0,0,0,0.3) inset;
}
} }
} }

View file

@ -0,0 +1,13 @@
#view-review {
background-color: #494949;
slide-to-accept, slide-to-accept-success {
margin-bottom: constant(safe-area-inset-bottom); /* iOS 11.0 */
margin-bottom: env(safe-area-inset-bottom); /* iOS 11.2 */
}
.fee-summary {
position: absolute;
bottom: 92px;
}
}

View file

@ -50,3 +50,4 @@
@import "includes/logOptions"; @import "includes/logOptions";
@import "includes/checkBar"; @import "includes/checkBar";
@import "cashScan"; @import "cashScan";
@import "review";

11
www/img/icon-bookmark.svg Normal file
View file

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11.25 15">
<defs>
<style>
.cls-1 {
fill: #444;
opacity: 0.564;
}
</style>
</defs>
<path id="_ionicons_svg_md-bookmark" class="cls-1" d="M121.688,64h-8.125A1.567,1.567,0,0,0,112,65.563V79l5.625-2.5L123.25,79V65.563A1.567,1.567,0,0,0,121.688,64Z" transform="translate(-112 -64)"/>
</svg>

After

Width:  |  Height:  |  Size: 381 B

116
www/views/review.html Normal file
View file

@ -0,0 +1,116 @@
<ion-view id="view-review" hide-tabs>
<ion-nav-bar class="bar-royal">
<ion-nav-title>
{{'Review Transaction' | translate}}
</ion-nav-title>
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<ion-content class="padded-bottom-cta-with-summary bg-neutral"
ng-init="memoExpanded = false">
<div class="header">
<div class="content">
<p translate>You are sending</p>
<p class="large">{{vm.primaryAmount}} {{vm.primaryCurrency}}</amount></p>
<p ng-show="vm.secondaryAmount">{{vm.secondaryAmount}} {{vm.secondaryCurrency}}</p>
</div>
</div>
<div class="content-frame negative-top">
<div class="card card-gutter-compact">
<div class="item item-compact" translate>From:</div>
<div class="item item-gutterless item-complex item-avatar">
<div class="item-content item-content-avatar">
<i class="icon big-icon-svg theme-circle theme-circle-services">
<div class="bg icon-wallet"
style="background-color: {{vm.origin.color}}"
></div>
</i>
<h2>{{vm.origin.name}} <span class="highlight" style="color: {{vm.origin.currencyColor}}">({{vm.origin.currency}})</span></h2>
<p ng-show="vm.origin.balanceAmount">{{vm.origin.balanceAmount}} {{vm.origin.balanceCurrency}}</p>
</div>
</div>
</div>
<div class="card card-gutter-compact">
<div class="item item-compact" translate>To:</div>
<div class="item item-gutterless item-complex item-avatar">
<div class="item-content item-content-avatar"
ng-if="vm.destination.kind === 'contact' || vm.destination.kind === 'wallet'">
<img src="img/contact-placeholder.svg" class="bg" ng-if="vm.destination.kind === 'contact'">
<i class="icon big-icon-svg theme-circle theme-circle-services" ng-if="vm.destination.kind === 'wallet'">
<div class="bg icon-wallet"
style="background-color: {{vm.destination.color}}"
></div>
</i>
<h2>{{vm.destination.name}}<span class="highlight" style="color: {{vm.destination.currencyColor}}" ng-if="vm.destination.currency"> ({{vm.destination.currency}})</span></h2></h2>
<p ng-if="vm.destination.balanceAmount">{{vm.destination.balanceAmount}} {{vm.destination.balanceCurrency}}</p>
</div>
<div class="item-content item-content-compact" ng-init="addressExpanded = false" ng-if="vm.destination.kind === 'address'">
<div class="address" ng-class="{ 'expanded': addressExpanded }" ng-click="addressExpanded = !addressExpanded"><span class="prefix">qz9cq</span><span class="mid">q5pryv9hnqwa8q8mccmynk9uf4vlu5nxer</span><span class="suffix">pzmc</span></div>
</div>
</div>
</div>
<div class="expand-content-frame">
<div class="action-minor mt-negative text-right expand-content-trigger"
ng-class="{ 'expand-content-revealed': memoExpanded }"
ng-click="memoExpanded = !memoExpanded">
<img src="img/icon-bookmark.svg" class="action-icon">
<span class="action-text">Add personal note</span>
</div>
<div class="card card-gutter-compact expand-content"
ng-class="{ 'expand-content-revealed': memoExpanded }">
<div class="item item-compact" translate>Personal Note:</div>
<div class="item">
<div class="item-content">
<textarea elastic placeholder="{{btx.note.body || btx.message || 'Enter text here'}}" class="elastic"></textarea>
</div>
</div>
</div>
</div>
</div>
</ion-content>
<div class="fee-summary">
<div class="fee-fiat positive">Fee: Less than 1 cent</div>
<div class="fee-crypto"
ng-init="fee = {value: '0.00195823', currency: 'BCH'};">
<amount
value="fee.value"
currency="fee.currency"></amount>
</div>
</div>
<click-to-accept
ng-click="approve(tx, wallet, statusChangeHandler)"
ng-if="(!isCordova || isWindowsPhoneApp) && wallet"
click-send-status="sendStatus"
is-disabled="!wallet">
{{buttonText}}
</click-to-accept>
<slide-to-accept
ng-if="isCordova && !isWindowsPhoneApp && wallet"
slide-on-confirm="approve(tx, wallet, statusChangeHandler)"
slide-send-status="sendStatus"
is-disabled="!wallet">
{{buttonText}}
</slide-to-accept>
<slide-to-accept-success
slide-success-show="sendStatus === 'success'"
slide-success-on-confirm="onSuccessConfirm()"
slide-success-hide-on-confirm="true">
<span ng-show="wallet.m == 1 && (wallet.canSign() || wallet.isPrivKeyExternal())" translate>Payment Sent</span>
<span ng-show="wallet.m > 1 && (wallet.canSign() || wallet.isPrivKeyExternal())" translate>Proposal Created</span>
<span ng-show="!wallet.canSign() && !wallet.isPrivKeyExternal()" translate>Transaction Created</span>
</slide-to-accept-success>
<wallet-selector
wallet-selector-title="walletSelectorTitle"
wallet-selector-wallets="wallets"
wallet-selector-selected-wallet="wallet"
wallet-selector-show="walletSelector"
wallet-selector-on-select="onWalletSelect"
wallet-selector-display-balance-as-fiat="displayBalanceAsFiat">
</wallet-selector>
</ion-view>