diff --git a/public/index.html b/public/index.html index 56a114dec..a385dbe5e 100644 --- a/public/index.html +++ b/public/index.html @@ -27,6 +27,7 @@
+
+
diff --git a/public/views/includes/confirm-tx.html b/public/views/includes/confirm-tx.html index 8dc2268b2..98b507b19 100644 --- a/public/views/includes/confirm-tx.html +++ b/public/views/includes/confirm-tx.html @@ -1,42 +1,40 @@ +
-
-
+
-
-
-
-

Confirm transaction

- -
    -
  • - Amount - {{home.confirmTxPopup.amountStr}} - {{home.confirmTxPopup.alternativeAmountStr}} - -
  • -
  • - Fee - {{home.confirmTxPopup.feeStr}} -
  • -
- -
+
+

Confirm transaction

-
-
- +
+
{{tx.amountStr}}
+
{{tx.alternativeAmountStr}}
+ +
+ + + + Multiple recipients +
-
- +
+ Fee: {{tx.feeStr}} +
+
+
+ +
+
+ +
diff --git a/public/views/includes/password.html b/public/views/includes/password.html index 6df98bbce..3866c86f4 100644 --- a/public/views/includes/password.html +++ b/public/views/includes/password.html @@ -1,5 +1,5 @@ -
+
-
+
{{error|translate}}
-
- The payment was removed by creator +
+
+ The payment was removed by creator +
-
+
-
-
diff --git a/src/css/main.css b/src/css/main.css index c3ee54f83..ea456aad2 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -1373,9 +1373,30 @@ input.ng-invalid-match, input.ng-invalid-match:focus { } } +/* Confirmation popup */ + +.confirmTxModal { + background: white; + border-radius: 5px; + position: absolute; + width: 90%; + left: 0; + right: 0; + margin: 15% auto; + z-index: 1100; + text-align: center; +} + +.confirmHead { + padding: 10px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +/*******************/ + .alertModal { background: #FFFFFF; - box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.50); border-radius: 5px; position: absolute; width: 90%; @@ -1386,7 +1407,6 @@ input.ng-invalid-match, input.ng-invalid-match:focus { .passModal { background: #FFFFFF; - box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.50); border-radius: 5px; position: absolute; width: 90%; @@ -1395,12 +1415,12 @@ input.ng-invalid-match, input.ng-invalid-match:focus { z-index: 1100; } -.passModalMask { +.modalMask { position: absolute; width: 100%; height: 100%; z-index: 1099; - opacity:0.3; + opacity:0.8; background: black; } diff --git a/src/js/controllers/confirmTx.js b/src/js/controllers/confirmTx.js new file mode 100644 index 000000000..05dfa8b02 --- /dev/null +++ b/src/js/controllers/confirmTx.js @@ -0,0 +1,13 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('confirmTxController', function() { + + this.close = function(cb) { + return cb(); + }; + + this.accept = function(cb) { + return cb(true); + }; + +}); diff --git a/src/js/controllers/index.js b/src/js/controllers/index.js index 928c830e9..2df9bb817 100644 --- a/src/js/controllers/index.js +++ b/src/js/controllers/index.js @@ -391,7 +391,6 @@ angular.module('copayApp.controllers').controller('indexController', function($r self.setFeeAndSendMax = function(cb) { - self.feeToSendMaxStr = null; self.availableMaxBalance = null; self.currentFeePerKb = null; @@ -1453,6 +1452,19 @@ angular.module('copayApp.controllers').controller('indexController', function($r self.setTab(tab, reset); }); + $rootScope.$on('Local/NeedConfirmation', function(event, txp, cb) { + self.confirmTx = { + txp : txFormatService.processTx(txp), + callback: function(accept) { + self.confirmTx = null; + return cb(accept); + } + }; + $timeout(function() { + $rootScope.$apply(); + }); + }); + $rootScope.$on('Local/NeedsPassword', function(event, isSetup, cb) { self.askPassword = { isSetup: isSetup, diff --git a/src/js/controllers/walletHome.js b/src/js/controllers/walletHome.js index 737849652..688f4566a 100644 --- a/src/js/controllers/walletHome.js +++ b/src/js/controllers/walletHome.js @@ -771,6 +771,8 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi var currentSpendUnconfirmed = configWallet.spendUnconfirmed; var currentFeeLevel = walletSettings.feeLevel || 'normal'; + var outputs = []; + this.resetError(); if (isCordova && this.isWindowsPhoneApp) { @@ -793,14 +795,6 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi return self.setSendError(gettext(msg)); } - var getFee = function(cb) { - if (self.lockedCurrentFeePerKb) { - cb(null, self.lockedCurrentFeePerKb); - } else { - feeService.getCurrentFeeValue(currentFeeLevel, cb); - } - }; - $timeout(function() { var paypro = self._paypro; var address, amount; @@ -808,57 +802,88 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi address = form.address.$modelValue; amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0)); + outputs.push({ + 'toAddress' : address, + 'amount': amount, + 'message': comment + }); + txSignService.prepare(function(err) { if (err) { return self.setSendError(err); } + + var opts = { + toAddress: address, + amount: amount, + outputs: outputs, + message: comment, + payProUrl: paypro ? paypro.url : null, + lockedCurrentFeePerKb: self.lockedCurrentFeePerKb + }; + self.setOngoingProcess(gettextCatalog.getString('Creating transaction')); - getFee(function(err, feePerKb) { - if (err) $log.debug(err); - fc.sendTxProposal({ - toAddress: address, - amount: amount, - message: comment, - payProUrl: paypro ? paypro.url : null, - feePerKb: feePerKb, - excludeUnconfirmedUtxos: currentSpendUnconfirmed ? false : true - }, function(err, txp) { - if (err) { - self.setOngoingProcess(); - return self.setSendError(err); - } + txSignService.createTx(opts, function(err, txp) { + self.setOngoingProcess(); + if (err) { + return self.setSendError(err); + } - if (!fc.canSign() && !fc.isPrivKeyExternal()) { - self.setOngoingProcess(); - $log.info('No signing proposal: No private key') - self.resetForm(); - txStatus.notify(txp, function() { - return $scope.$emit('Local/TxProposalAction'); - }); - return; - } - - txSignService.signAndBroadcast(txp, { - reporterFn: self.setOngoingProcess.bind(self) - }, function(err, txp) { - self.resetForm(); - if (err) { - self.error = err.message ? err.message : gettext('The payment was created but could not be completed. Please try again from home screen'); - $scope.$emit('Local/TxProposalAction'); - $timeout(function() { - $scope.$digest(); - }, 1); - } else { - go.walletHome(); - txStatus.notify(txp, function() { - $scope.$emit('Local/TxProposalAction', txp.status == 'broadcasted'); - }); - }; + if (!fc.canSign() && !fc.isPrivKeyExternal()) { + self.setOngoingProcess(); + $log.info('No signing proposal: No private key'); + self.resetForm(); + txStatus.notify(txp, function() { + return $scope.$emit('Local/TxProposalAction'); }); - }); + return; + } else { + $rootScope.$emit('Local/NeedConfirmation', txp, function(accept) { + if (accept) self.acceptTx(txp); + else self.resetForm(); + }); + } }); + }); }, 100); + }; + + this.acceptTx = function(txp) { + var self = this; + this.confirmTxPopup = null; + this.setOngoingProcess(gettextCatalog.getString('Sending transaction')); + txSignService.publishTx(txp.id, function(err) { + self.setOngoingProcess(); + if (err) { + $log.debug(err); + self.setSendError(err); + } else { + self.resetForm(); + // self.signAndBroadcastTx(txp); + } + }); + }; + + this.signAndBroadcastTx = function() { + var self = this; + txSignService.signAndBroadcast(txp, { + reporterFn: self.setOngoingProcess.bind(self) + }, function(err, txp) { + self.resetForm(); + if (err) { + self.error = err.message ? err.message : gettext('The payment was created but could not be completed. Please try again from home screen'); + $scope.$emit('Local/TxProposalAction'); + $timeout(function() { + $scope.$digest(); + }, 1); + } else { + go.walletHome(); + txStatus.notify(txp, function() { + $scope.$emit('Local/TxProposalAction', txp.status == 'broadcasted'); + }); + }; + }); }; this.setForm = function(to, amount, comment) { diff --git a/src/js/services/txFormatService.js b/src/js/services/txFormatService.js index 71bd41825..ede78468c 100644 --- a/src/js/services/txFormatService.js +++ b/src/js/services/txFormatService.js @@ -30,6 +30,7 @@ angular.module('copayApp.services').factory('txFormatService', function(profileS tx.hasMultiplesOutputs = true; tx.recipientCount = outputs; } + tx.toAddress = tx.outputs[0].toAddress; tx.amount = lodash.reduce(tx.outputs, function(total, o) { o.amountStr = formatAmountStr(o.amount); o.alternativeAmountStr = formatAlternativeStr(o.amount); diff --git a/src/js/services/txSignService.js b/src/js/services/txSignService.js index e32f79920..daf9e0ca1 100644 --- a/src/js/services/txSignService.js +++ b/src/js/services/txSignService.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.services').factory('txSignService', function($rootScope, profileService, gettextCatalog, lodash, trezor, ledger, configService, bwsError, $log) { +angular.module('copayApp.services').factory('txSignService', function($rootScope, profileService, gettextCatalog, lodash, trezor, ledger, configService, bwsError, $log, feeService) { var root = {}; var reportSigningStatus = function(opts) { @@ -85,8 +85,43 @@ angular.module('copayApp.services').factory('txSignService', function($rootScope }; return cb(); + }); }); + }; + + root.createTx = function(opts, cb) { + var fc = profileService.focusedClient; + var config = configService.getSync(); + var configWallet = config.wallet; + var walletSettings = configWallet.settings; + + var currentSpendUnconfirmed = configWallet.spendUnconfirmed; + var currentFeeLevel = walletSettings.feeLevel || 'normal'; + + var getFee = function(cb) { + if (opts.lockedCurrentFeePerKb) { + cb(null, opts.lockedCurrentFeePerKb); + } else { + feeService.getCurrentFeeValue(currentFeeLevel, cb); + } + }; + + getFee(function(err, feePerKb) { + if (err) $log.debug(err); + fc.createTxProposal(opts, function(err, txp) { + if (err) return cb(err); + else return cb(null, txp); + }); + }); + }; + + root.publishTx = function(txId, cb) { + var fc = profileService.focusedClient; + fc.publishTxProposal(txId, function(err) { + if (err) return cb(err); + else return cb(); + }); }; var _signWithLedger = function(txp, cb) {