Sends wallet to wallet transaction with sound.

This commit is contained in:
Brendon Duncan 2018-08-03 19:14:33 +12:00
commit 5973b30551
2 changed files with 99 additions and 52 deletions

View file

@ -4,7 +4,7 @@ angular
.module('copayApp.controllers')
.controller('reviewController', reviewController);
function reviewController(addressbookService, bitcoinCashJsService, bitcore, bitcoreCash, bwcError, configService, feeService, gettextCatalog, $ionicLoading, $ionicModal, lodash, $log, ongoingProcess, platformInfo, popupService, profileService, $scope, $timeout, txFormatService, walletService) {
function reviewController(addressbookService, bitcoinCashJsService, bitcore, bitcoreCash, bwcError, configService, feeService, gettextCatalog, $ionicLoading, $ionicModal, lodash, $log, ongoingProcess, platformInfo, popupService, profileService, $scope, soundService, $state, $timeout, txConfirmNotification, txFormatService, walletService) {
var vm = this;
vm.buttonText = '';
@ -24,16 +24,15 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
vm.fiatCurrency = '';
vm.feeIsHigh = false;
vm.feeLessThanACent = false;
vm.isCordova = platformInfo.isCordova;
vm.notReadyMessage = '';
vm.origin = {
balanceAmount: '',
balanceCurrency: '',
color: '',
currency: '',
currencyColor: '',
name: '',
};
vm.isCordova = platformInfo.isCordova;
vm.notReadyMessage = '';
vm.originWallet = null;
vm.primaryAmount = '';
vm.primaryCurrency = '';
vm.usingMerchantFee = false;
@ -41,7 +40,9 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
vm.secondaryAmount = '';
vm.secondaryCurrency = '';
vm.sendingTitle = gettextCatalog.getString('You are sending');
vm.sendStatus = '';
vm.thirdParty = false;
vm.wallet = null;
var config = null;
var coin = '';
@ -50,7 +51,6 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
var usingMerchantFee = false;
var destinationWalletId = '';
var originWalletId = '';
var originWallet;
var priceDisplayIsFiat = true;
var satoshis = null;
var toAddress = '';
@ -68,11 +68,9 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
satoshis = parseInt(data.stateParams.amount, 10);
toAddress = data.stateParams.toAddr;
originWallet = profileService.getWallet(originWalletId);
vm.origin.currency = originWallet.coin.toUpperCase();
vm.origin.color = originWallet.color;
vm.origin.name = originWallet.name;
coin = originWallet.coin;
vm.originWallet = profileService.getWallet(originWalletId);
vm.origin.currency = vm.originWallet.coin.toUpperCase();
coin = vm.originWallet.coin;
if (data.stateParams.thirdParty) {
vm.thirdParty = JSON.parse(data.stateParams.thirdParty); // Parse stringified JSON-object
@ -93,20 +91,20 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
} else {
config = configCache;
priceDisplayIsFiat = config.wallet.settings.priceDisplay === 'fiat';
vm.origin.currencyColor = originWallet.coin === 'btc' ? config.bitcoinWalletColor : config.bitcoinCashWalletColor;
vm.origin.currencyColor = vm.originWallet.coin === 'btc' ? config.bitcoinWalletColor : config.bitcoinCashWalletColor;
unitFromSat = 1 / config.wallet.settings.unitToSatoshi;
}
updateSendAmounts();
getOriginWalletBalance(originWallet);
getOriginWalletBalance(vm.originWallet);
handleDestinationAsAddress(toAddress, coin);
handleDestinationAsWallet(data.stateParams.toWalletId);
createVanityTransaction(data);
});
}
vm.approve = function(onSendStatusChange) {
vm.approve = function() {
if (!tx || !originWallet) return;
if (!tx || !vm.originWallet) return;
if ($scope.paymentExpired) {
popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.'));
@ -117,42 +115,42 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
return;
}
ongoingProcess.set('creatingTx', true, onSendStatusChange);
getTxp(lodash.clone(tx), originWallet, false, function(err, txp) {
ongoingProcess.set('creatingTx', false, onSendStatusChange);
ongoingProcess.set('creatingTx', true, statusChangeHandler);
getTxp(lodash.clone(tx), vm.originWallet, false, function(err, txp) {
ongoingProcess.set('creatingTx', false, statusChangeHandler);
if (err) return;
// confirm txs for more that 20usd, if not spending/touchid is enabled
function confirmTx(cb) {
if (walletService.isEncrypted(originWallet))
if (walletService.isEncrypted(vm.originWallet))
return cb();
var amountUsd = parseFloat(txFormatService.formatToUSD(originWallet.coin, txp.amount));
var amountUsd = parseFloat(txFormatService.formatToUSD(vm.originWallet.coin, txp.amount));
return cb();
};
function publishAndSign() {
if (!originWallet.canSign() && !originWallet.isPrivKeyExternal()) {
if (!vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal()) {
$log.info('No signing proposal: No private key');
return walletService.onlyPublish(originWallet, txp, function(err) {
return walletService.onlyPublish(vm.originWallet, txp, function(err) {
if (err) setSendError(err);
}, onSendStatusChange);
}, statusChangeHandler);
}
walletService.publishAndSign(originWallet, txp, function(err, txp) {
walletService.publishAndSign(vm.originWallet, txp, function(err, txp) {
if (err) return setSendError(err);
if (config.confirmedTxsNotifications && config.confirmedTxsNotifications.enabled) {
txConfirmNotification.subscribe(originWallet, {
txConfirmNotification.subscribe(vm.originWallet, {
txid: txp.txid
});
}
}, onSendStatusChange);
}, statusChangeHandler);
};
confirmTx(function(nok) {
if (nok) {
$scope.sendStatus = '';
vm.sendStatus = '';
$timeout(function() {
$scope.$apply();
});
@ -172,7 +170,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
scope.network = tx.network;
scope.feeLevel = tx.feeLevel;
scope.noSave = true;
scope.coin = originWallet.coin;
scope.coin = vm.originWallet.coin;
if (usingCustomFee) {
scope.customFeePerKB = tx.feeRate;
@ -202,7 +200,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
tx.feeLevel = newFeeLevel;
if (usingCustomFee) tx.feeRate = parseInt(customFeePerKB);
updateTx(tx, originWallet, {
updateTx(tx, vm.originWallet, {
clearCache: true,
dryRun: true
}, function() {});
@ -228,7 +226,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
toEmail: vm.destination.email || null,
toColor: vm.destination.color || null,
network: false,
coin: originWallet.coin,
coin: vm.originWallet.coin,
txp: {},
};
@ -281,7 +279,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
}
}
function getOriginWalletBalance(originWallet) {
var balanceText = getWalletBalanceDisplayText(originWallet);
var balanceText = getWalletBalanceDisplayText(vm.originWallet);
vm.origin.balanceAmount = balanceText.amount;
vm.origin.balanceCurrency = balanceText.currency;
}
@ -476,6 +474,18 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
});
}
vm.onSuccessConfirm = function() {
vm.sendStatus = '';
$ionicHistory.nextViewOptions({
disableAnimate: true,
historyRoot: true
});
$state.go('tabs.send').then(function() {
$ionicHistory.clearHistory();
$state.transitionTo('tabs.home');
});
};
function setButtonText(isMultisig, isPayPro) {
if (isPayPro) {
if (vm.isCordova) {
@ -536,12 +546,12 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
vm.showAddress = false;
setButtonText(originWallet.credentials.m > 1, !!tx.paypro);
setButtonText(vm.originWallet.credentials.m > 1, !!tx.paypro);
if (tx.paypro)
_paymentTimeControl(tx.paypro.expires);
updateTx(tx, originWallet, {
updateTx(tx, vm.originWallet, {
dryRun: true
}, function(err) {
$timeout(function() {
@ -562,6 +572,43 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
// }
// });
}
function statusChangeHandler(processName, showName, isOn) {
$log.debug('statusChangeHandler: ', processName, showName, isOn);
if (
(
processName === 'broadcastingTx' ||
((processName === 'signingTx') && vm.originWallet.m > 1) ||
(processName == 'sendingTx' && !vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal())
) && !isOn) {
$scope.sendStatus = 'success';
if ($state.current.name === "tabs.send.review") { // XX SP: Otherwise all open wallets on other devices play this sound if you have been in a send flow before on that device.
soundService.play('misc/payment_sent.mp3');
}
var channel = "firebase";
if (platformInfo.isNW) {
channel = "ga";
}
// When displaying Fiat, if the formatting fails, the crypto will be the primary amount.
var amount = priceDisplayIsFiat ? vm.secondaryAmount || vm.primaryAmount : vm.primaryAmount;
var log = new window.BitAnalytics.LogEvent("transfer_success", [{
"coin": vm.originWallet.coin,
"type": "outgoing",
"amount": amount,
"fees": vm.feeCrypto
}], [channel, "adjust"]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
$timeout(function() {
$scope.$digest();
}, 100);
} else if (showName) {
$scope.sendStatus = showName;
}
};
function updateTx(tx, wallet, opts, cb) {
ongoingProcess.set('calculatingFee', true);
@ -589,8 +636,8 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
// updateAmount();
// refresh();
var feeServiceLevel = usingMerchantFee && originWallet.coin == 'btc' ? 'urgent' : tx.feeLevel;
feeService.getFeeRate(originWallet.coin, tx.network, feeServiceLevel, function(err, feeRate) {
var feeServiceLevel = usingMerchantFee && vm.originWallet.coin == 'btc' ? 'urgent' : tx.feeLevel;
feeService.getFeeRate(vm.originWallet.coin, tx.network, feeServiceLevel, function(err, feeRate) {
if (err) {
ongoingProcess.set('calculatingFee', false);
return cb(err);

View file

@ -25,10 +25,10 @@
<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}}"
style="background-color: {{vm.originWallet.color}}"
></div>
</i>
<h2>{{vm.origin.name}} <span class="highlight" style="color: {{vm.origin.currencyColor}}">({{vm.origin.currency}})</span></h2>
<h2>{{vm.originWallet.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>
@ -73,7 +73,7 @@
</ion-content>
<div class="fee-summary">
<div class="fee-fiat" ng-if="vm.feeLessThanACent">Fee: Less than 1 cent</div>
<div class="fee-fiat positive" ng-if="vm.feeLessThanACent">Fee: Less than 1 cent</div>
<div class="fee-fiat" ng-class="vm.feeIsHigh ? 'negative' : 'positive'" ng-if="!vm.feeLessThanACent">Fee: {{vm.feeFiat}} {{vm.feeCurrency}}</div>
<div class="fee-crypto" ng-if="vm.feeCrypto">
{{vm.feeCrypto}} {{vm.origin.currency}}
@ -81,25 +81,25 @@
</div>
<click-to-accept
ng-click="approve(tx, wallet, statusChangeHandler)"
ng-if="(!vm.isCordova)"
click-send-status="sendStatus"
is-disabled="!wallet">
{{buttonText}}
ng-click="vm.approve()"
ng-if="!vm.isCordova"
click-send-status="vm.sendStatus"
is-disabled="!vm.readyToSend">
{{vm.buttonText}}
</click-to-accept>
<slide-to-accept
ng-if="vm.isCordova"
slide-on-confirm="approve(tx, wallet, statusChangeHandler)"
slide-send-status="sendStatus"
is-disabled="!wallet">
{{buttonText}}
slide-on-confirm="vm.approve()"
slide-send-status="vm.sendStatus"
is-disabled="!vm.readyToSend">
{{vm.buttonText}}
</slide-to-accept>
<slide-to-accept-success
slide-success-show="sendStatus === 'success'"
slide-success-on-confirm="onSuccessConfirm()"
slide-success-show="vm.sendStatus === 'success'"
slide-success-on-confirm="vm.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>
<span ng-show="vm.originWallet.m == 1 && (vm.originWallet.canSign() || vm.originWallet.isPrivKeyExternal())" translate>Payment Sent</span>
<span ng-show="vm.originWallet.m > 1 && (vm.originWallet.canSign() || vm.originWallet.isPrivKeyExternal())" translate>Proposal Created</span>
<span ng-show="!vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal()" translate>Transaction Created</span>
</slide-to-accept-success>
</ion-view>