diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index 93bab7a0c..f4f8d9d72 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -1,22 +1,21 @@ 'use strict'; -angular.module('copayApp.controllers').controller('amountController', function($rootScope, $scope, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, bitpayCardService, popupService, bwcError, payproService, amazonService, profileService) { - +angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, $ionicPopover, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, bitpayCardService, popupService, bwcError, payproService, profileService, bitcore, amazonService) { var unitToSatoshi; var satToUnit; var unitDecimals; var satToBtc; - var self = $scope.self; var SMALL_FONT_SIZE_LIMIT = 10; var LENGTH_EXPRESSION_LIMIT = 19; + var MENU_ITEM_HEIGHT = 55; $scope.$on('$ionicView.leave', function() { angular.element($window).off('keydown'); }); $scope.$on("$ionicView.beforeEnter", function(event, data) { - $scope.isGiftCard = data.stateParams.isGiftCard; + $scope.showMenu = $ionicHistory.backView().stateName == 'tabs.send'; $scope.isWallet = data.stateParams.isWallet; $scope.cardId = data.stateParams.cardId; $scope.toAddress = data.stateParams.toAddress; @@ -52,8 +51,7 @@ angular.module('copayApp.controllers').controller('amountController', function($ $timeout(function() { $scope.$apply(); - }, 10); - + }); }); var config = configService.getSync().wallet.settings; @@ -80,6 +78,35 @@ angular.module('copayApp.controllers').controller('amountController', function($ }, 10); }); + $scope.showSendMaxMenu = function($event) { + var sendMaxObj = { + text: gettextCatalog.getString('Send max amount'), + action: setSendMax, + }; + + $scope.items = [sendMaxObj]; + $scope.height = $scope.items.length * MENU_ITEM_HEIGHT; + + $ionicPopover.fromTemplateUrl('views/includes/menu-popover.html', { + scope: $scope + }).then(function(popover) { + $scope.menu = popover; + $scope.menu.show($event); + }); + }; + + function setSendMax() { + $scope.menu.hide(); + $state.transitionTo('tabs.send.confirm', { + isWallet: $scope.isWallet, + toAmount: null, + toAddress: $scope.toAddress, + toName: $scope.toName, + toEmail: $scope.toEmail, + useSendMax: true, + }); + }; + $scope.toggleAlternative = function() { $scope.showAlternativeAmount = !$scope.showAlternativeAmount; @@ -124,7 +151,6 @@ angular.module('copayApp.controllers').controller('amountController', function($ function isExpression(val) { var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/; - return regex.test(val); }; @@ -137,7 +163,6 @@ angular.module('copayApp.controllers').controller('amountController', function($ $scope.resetAmount = function() { $scope.amount = $scope.alternativeResult = $scope.amountResult = $scope.globalResult = ''; $scope.allowSend = false; - checkFontSize(); }; @@ -251,7 +276,7 @@ angular.module('copayApp.controllers').controller('amountController', function($ onlyComplete: true, network: 'livenet', })[0].id; - } catch(err) { + } catch (err) { ongoingProcess.set('Preparing transaction...', false); popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('No wallet found!')); return; diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 4919263d8..37e542291 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -1,18 +1,19 @@ 'use strict'; -angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, gettext, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, amazonService) { +angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, gettext, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, amazonService) { var cachedTxp = {}; + var toAmount; var isChromeApp = platformInfo.isChromeApp; var countDown = null; var giftCardAmountUSD; var giftCardAccessKey; var giftCardInvoiceTime; var giftCardUUID; + var cachedSendMax = {}; $scope.isCordova = platformInfo.isCordova; $ionicConfig.views.swipeBackEnabled(false); $scope.$on("$ionicView.beforeEnter", function(event, data) { - // Amazon.com Gift Card parameters $scope.isGiftCard = data.stateParams.isGiftCard; giftCardAmountUSD = data.stateParams.giftCardAmountUSD; @@ -20,97 +21,201 @@ angular.module('copayApp.controllers').controller('confirmController', function( giftCardInvoiceTime = data.stateParams.giftCardInvoiceTime; giftCardUUID = data.stateParams.giftCardUUID; + toAmount = data.stateParams.toAmount; + cachedSendMax = {}; + $scope.useSendMax = data.stateParams.useSendMax == 'true' ? true : false; $scope.isWallet = data.stateParams.isWallet; $scope.cardId = data.stateParams.cardId; - $scope.toAmount = data.stateParams.toAmount; $scope.toAddress = data.stateParams.toAddress; $scope.toName = data.stateParams.toName; $scope.toEmail = data.stateParams.toEmail; $scope.description = data.stateParams.description; $scope.paypro = data.stateParams.paypro; + $scope.insufficientFunds = false; + $scope.noMatchingWallet = false; $scope.paymentExpired = { value: false }; $scope.remainingTimeStr = { value: null }; - initConfirm(); - }); - - var initConfirm = function() { - // TODO (URL , etc) - if (!$scope.toAddress || !$scope.toAmount) { - $log.error('Bad params at amount'); - throw ('bad params'); - } var config = configService.getSync().wallet; $scope.feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal'; + $scope.network = (new bitcore.Address($scope.toAddress)).network.name; + resetValues(); + setwallets(); + }); - $scope.toAmount = parseInt($scope.toAmount); - $scope.amountStr = txFormatService.formatAmountStr($scope.toAmount); - $scope.displayAmount = getDisplayAmount($scope.amountStr); - $scope.displayUnit = getDisplayUnit($scope.amountStr); - - var networkName = (new bitcore.Address($scope.toAddress)).network.name; - $scope.network = networkName; - - $scope.insuffientFunds = false; - $scope.noMatchingWallet = false; - - var wallets = profileService.getWallets({ + function setwallets() { + $scope.wallets = profileService.getWallets({ onlyComplete: true, - network: networkName, + network: $scope.network, n: $scope.isGiftCard ? true : false }); - if (!wallets || !wallets.length) { + if (!$scope.wallets || !$scope.wallets.length) { $scope.noMatchingWallet = true; + if ($scope.paypro) { + displayValues(); + } + $timeout(function() { + $scope.$apply(); + }); + return; } var filteredWallets = []; var index = 0; var enoughFunds = false; - lodash.each(wallets, function(w) { + lodash.each($scope.wallets, function(w) { walletService.getStatus(w, {}, function(err, status) { if (err || !status) { $log.error(err); } else { w.status = status; if (!status.availableBalanceSat) $log.debug('No balance available in: ' + w.name); - if (status.availableBalanceSat > $scope.toAmount) { + if (status.availableBalanceSat > toAmount) { filteredWallets.push(w); enoughFunds = true; } } - if (++index == wallets.length) { + if (++index == $scope.wallets.length) { if (!lodash.isEmpty(filteredWallets)) { $scope.wallets = lodash.clone(filteredWallets); - setWallet($scope.wallets[0]); + if ($scope.useSendMax) $scope.showWalletSelector(); + else initConfirm(); } else { - - if (!enoughFunds) - $scope.insuffientFunds = true; - + if (!enoughFunds) $scope.insufficientFunds = true; $log.warn('No wallet available to make the payment'); - $timeout(function() { - $scope.$apply(); - }); } + $timeout(function() { + $scope.$apply(); + }); } }); }); + }; - txFormatService.formatAlternativeStr($scope.toAmount, function(v) { + var initConfirm = function() { + if ($scope.paypro) _paymentTimeControl($scope.paypro.expires); + + displayValues(); + $scope.showWalletSelector(); + + $timeout(function() { + $scope.$apply(); + }); + }; + + function displayValues() { + toAmount = parseInt(toAmount); + $scope.amountStr = txFormatService.formatAmountStr(toAmount); + $scope.displayAmount = getDisplayAmount($scope.amountStr); + $scope.displayUnit = getDisplayUnit($scope.amountStr); + txFormatService.formatAlternativeStr(toAmount, function(v) { $scope.alternativeAmountStr = v; }); + }; - if($scope.paypro) { - _paymentTimeControl($scope.paypro.expires); - } + function resetValues() { + $scope.displayAmount = $scope.displayUnit = $scope.fee = $scope.alternativeAmountStr = $scope.insufficientFunds = $scope.noMatchingWallet = null; + }; + $scope.getSendMaxInfo = function() { + resetValues(); + + ongoingProcess.set('gettingFeeLevels', true); + feeService.getCurrentFeeValue($scope.network, function(err, feePerKb) { + ongoingProcess.set('gettingFeeLevels', false); + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err.message); + return; + } + var config = configService.getSync().wallet; + + ongoingProcess.set('retrievingInputs', true); + walletService.getSendMaxInfo($scope.wallet, { + feePerKb: feePerKb, + excludeUnconfirmedUtxos: !config.spendUnconfirmed, + returnInputs: true, + }, function(err, resp) { + ongoingProcess.set('retrievingInputs', false); + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; + } + + if (resp.amount == 0) { + $scope.insufficientFunds = true; + popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee')); + return; + } + + $scope.sendMaxInfo = { + sendMax: true, + amount: resp.amount, + inputs: resp.inputs, + fee: resp.fee, + feePerKb: feePerKb, + }; + + cachedSendMax[$scope.wallet.id] = $scope.sendMaxInfo; + + var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", { + fee: txFormatService.formatAmountStr(resp.fee) + }); + var warningMsg = verifyExcludedUtxos(); + + if (!lodash.isEmpty(warningMsg)) + msg += '\n' + warningMsg; + + popupService.showAlert(null, msg, function() { + setSendMaxValues(resp); + + createTx($scope.wallet, true, function(err, txp) { + if (err) return; + cachedTxp[$scope.wallet.id] = txp; + apply(txp); + }); + }); + + function verifyExcludedUtxos() { + var warningMsg = []; + if (resp.utxosBelowFee > 0) { + warningMsg.push(gettextCatalog.getString("A total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", { + amountBelowFeeStr: txFormatService.formatAmountStr(resp.amountBelowFee) + })); + } + + if (resp.utxosAboveMaxSize > 0) { + warningMsg.push(gettextCatalog.getString("A total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded.", { + amountAboveMaxSizeStr: txFormatService.formatAmountStr(resp.amountAboveMaxSize) + })); + } + return warningMsg.join('\n'); + }; + }); + }); + }; + + function setSendMaxValues(data) { + resetValues(); + var config = configService.getSync().wallet; + var unitName = config.settings.unitName; + var unitToSatoshi = config.settings.unitToSatoshi; + var satToUnit = 1 / unitToSatoshi; + var unitDecimals = config.settings.unitDecimals; + + $scope.displayAmount = txFormatService.formatAmount(data.amount, true); + $scope.displayUnit = unitName; + $scope.fee = txFormatService.formatAmountStr(data.fee); + toAmount = parseFloat((data.amount * satToUnit).toFixed(unitDecimals)); + txFormatService.formatAlternativeStr(data.amount, function(v) { + $scope.alternativeAmountStr = v; + }); $timeout(function() { $scope.$apply(); }); @@ -120,24 +225,24 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.approve(); }); - $scope.$on('Wallet/Changed', function(event, wallet) { - if (lodash.isEmpty(wallet)) { - $log.debug('No wallet provided'); - return; - } - $log.debug('Wallet changed: ' + wallet.name); - setWallet(wallet, true); - }); - $scope.showWalletSelector = function() { + if (!$scope.useSendMax && ($scope.insufficientFunds || $scope.noMatchingWallet)) return; $scope.showWallets = true; }; $scope.onWalletSelect = function(wallet) { - setWallet(wallet); + if ($scope.useSendMax) { + $scope.wallet = wallet; + if (cachedSendMax[wallet.id]) { + $log.debug('Send max cached for wallet:', wallet.id); + setSendMaxValues(cachedSendMax[wallet.id]); + return; + } + $scope.getSendMaxInfo(); + } else + setWallet(wallet); }; - $scope.showDescriptionPopup = function() { var message = gettextCatalog.getString('Add description'); var opts = { @@ -148,17 +253,17 @@ angular.module('copayApp.controllers').controller('confirmController', function( if (typeof res != 'undefined') $scope.description = res; $timeout(function() { $scope.$apply(); - }, 100); + }); }); }; function getDisplayAmount(amountStr) { - return amountStr.split(' ')[0]; - } + return $scope.amountStr.split(' ')[0]; + }; function getDisplayUnit(amountStr) { - return amountStr.split(' ')[1]; - } + return $scope.amountStr.split(' ')[1]; + }; function _paymentTimeControl(expirationTime) { $scope.paymentExpired.value = false; @@ -180,7 +285,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( var m = Math.floor(totalSecs / 60); var s = totalSecs % 60; $scope.remainingTimeStr.value = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2); - } + }; function setExpiredValues() { $scope.paymentExpired.value = true; @@ -189,19 +294,14 @@ angular.module('copayApp.controllers').controller('confirmController', function( $timeout(function() { $scope.$apply(); }); - } - } + }; + }; function setWallet(wallet, delayed) { var stop; $scope.wallet = wallet; $scope.fee = $scope.txp = null; - $timeout(function() { - $ionicScrollDelegate.resize(); - $scope.$apply(); - }, 10); - if (stop) { $timeout.cancel(stop); stop = null; @@ -218,31 +318,37 @@ angular.module('copayApp.controllers').controller('confirmController', function( }); }, delayed ? 2000 : 1); } - } + + $timeout(function() { + $ionicScrollDelegate.resize(); + $scope.$apply(); + }, 10); + }; var setSendError = function(msg) { $scope.sendStatus = ''; $timeout(function() { $scope.$apply(); }); - popupService.showAlert(gettextCatalog.getString('Error at confirm:'), msg); + popupService.showAlert(gettextCatalog.getString('Error at confirm'), msg); }; function apply(txp) { $scope.fee = txFormatService.formatAmountStr(txp.fee); $scope.txp = txp; - $scope.$apply(); - } + $timeout(function() { + $scope.$apply(); + }); + }; var createTx = function(wallet, dryRun, cb) { var config = configService.getSync().wallet; var currentSpendUnconfirmed = config.spendUnconfirmed; - var outputs = []; - var paypro = $scope.paypro; var toAddress = $scope.toAddress; - var toAmount = $scope.toAmount; var description = $scope.description; + var unitToSatoshi = config.settings.unitToSatoshi; + var unitDecimals = config.settings.unitDecimals; // ToDo: use a credential's (or fc's) function for this if (description && !wallet.credentials.sharedEncryptingKey) { @@ -257,28 +363,30 @@ angular.module('copayApp.controllers').controller('confirmController', function( return setSendError(msg); } - outputs.push({ - 'toAddress': toAddress, - 'amount': toAmount, - 'message': description - }); - var txp = {}; + var amount; - // TODO - if (!lodash.isEmpty($scope.sendMaxInfo)) { - txp.sendMax = true; + if ($scope.useSendMax) amount = parseFloat((toAmount * unitToSatoshi).toFixed(0)); + else amount = toAmount; + + txp.outputs = [{ + 'toAddress': toAddress, + 'amount': amount, + 'message': description + }]; + + if ($scope.sendMaxInfo) { txp.inputs = $scope.sendMaxInfo.inputs; txp.fee = $scope.sendMaxInfo.fee; - } + } else + txp.feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal'; - txp.outputs = outputs; txp.message = description; - if(paypro) { + + if (paypro) { txp.payProUrl = paypro.url; } - txp.excludeUnconfirmedUtxos = config.spendUnconfirmed ? false : true; - txp.feeLevel = config.settings && config.settings.feeLevel ? config.settings.feeLevel : 'normal'; + txp.excludeUnconfirmedUtxos = !currentSpendUnconfirmed; txp.dryRun = dryRun; walletService.createTx(wallet, txp, function(err, ctxp) { @@ -300,7 +408,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; $scope.approve = function(onSendStatusChange) { - if ($scope.paypro && $scope.paymentExpired.value) { popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.')); $scope.sendStatus = ''; @@ -375,7 +482,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( } else if (showName) { $scope.sendStatus = showName; } - } + }; $scope.statusChangeHandler = statusChangeHandler; diff --git a/src/js/controllers/paperWallet.js b/src/js/controllers/paperWallet.js index 32e584e8b..5d9be8376 100644 --- a/src/js/controllers/paperWallet.js +++ b/src/js/controllers/paperWallet.js @@ -60,7 +60,7 @@ angular.module('copayApp.controllers').controller('paperWalletController', $scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, null, function(err, testTx) { if (err) return cb(err); var rawTxLength = testTx.serialize().length; - feeService.getCurrentFeeValue($scope.wallet, function(err, feePerKB) { + feeService.getCurrentFeeValue('livenet', function(err, feePerKB) { var opts = {}; opts.fee = Math.round((feePerKB * rawTxLength) / 2000); $scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, opts, function(err, tx) { diff --git a/src/js/controllers/preferencesFee.js b/src/js/controllers/preferencesFee.js index f1a041438..d01f25262 100644 --- a/src/js/controllers/preferencesFee.js +++ b/src/js/controllers/preferencesFee.js @@ -1,10 +1,14 @@ 'use strict'; -angular.module('copayApp.controllers').controller('preferencesFeeController', function($scope, $timeout, $ionicHistory, gettextCatalog, configService, feeService, ongoingProcess) { +angular.module('copayApp.controllers').controller('preferencesFeeController', function($scope, $timeout, $ionicHistory, gettextCatalog, configService, feeService, ongoingProcess, popupService) { ongoingProcess.set('gettingFeeLevels', true); - feeService.getFeeLevels(function(levels) { + feeService.getFeeLevels(function(err, levels) { ongoingProcess.set('gettingFeeLevels', false); + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; + } $scope.feeLevels = levels; $scope.$apply(); }); diff --git a/src/js/routes.js b/src/js/routes.js index d86d0c8ab..4ef27d0a8 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -286,7 +286,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }) .state('tabs.send.confirm', { - url: '/confirm/:isWallet/:toAddress/:toName/:toAmount/:toEmail/:description', + url: '/confirm/:isWallet/:toAddress/:toName/:toAmount/:toEmail/:description/:useSendMax', views: { 'tab-send@tabs': { controller: 'confirmController', diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index be1a57160..6a9691ebc 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.services').factory('feeService', function($log, $stateParams, bwcService, walletService, configService, gettext, lodash, txFormatService) { +angular.module('copayApp.services').factory('feeService', function($log, $stateParams, bwcService, walletService, configService, gettext, lodash, txFormatService, gettextCatalog) { var root = {}; // Constant fee options to translate @@ -15,45 +15,48 @@ angular.module('copayApp.services').factory('feeService', function($log, $stateP return configService.getSync().wallet.settings.feeLevel || 'normal'; }; - root.getCurrentFeeValue = function(wallet, cb) { + root.getCurrentFeeValue = function(network, cb) { + network = network || 'livenet'; var feeLevel = root.getCurrentFeeLevel(); - wallet.getFeeLevels(wallet.credentials.network, function(err, levels) { - if (err) - return cb({ - message: 'Could not get dynamic fee' - }); + root.getFeeLevels(function(err, levels) { + if (err) return cb(err); - var feeLevelValue = lodash.find(levels, { + var feeLevelValue = lodash.find(levels[network], { level: feeLevel }); - if (!feeLevelValue || feeLevelValue.feePerKB == null) + + if (!feeLevelValue || !feeLevelValue.feePerKB) { return cb({ - message: 'Could not get dynamic fee for level: ' + feeLevel + message: gettextCatalog.getString("Could not get dynamic fee for level: {{feeLevel}}", { + feeLevel: feeLevel + }) }); + } var fee = feeLevelValue.feePerKB; $log.debug('Dynamic fee: ' + feeLevel + ' ' + fee + ' SAT'); + return cb(null, fee); }); }; root.getFeeLevels = function(cb) { var walletClient = bwcService.getClient(); - var unitName = configService.getSync().wallet.settings.unitName; walletClient.getFeeLevels('livenet', function(errLivenet, levelsLivenet) { walletClient.getFeeLevels('testnet', function(errTestnet, levelsTestnet) { - if (errLivenet || errTestnet) $log.debug('Could not get dynamic fee'); - else { + if (errLivenet || errTestnet) { + return cb(gettextCatalog.getString('Could not get dynamic fee')); + } else { for (var i = 0; i < 4; i++) { levelsLivenet[i]['feePerKBUnit'] = txFormatService.formatAmount(levelsLivenet[i].feePerKB) + ' ' + unitName; levelsTestnet[i]['feePerKBUnit'] = txFormatService.formatAmount(levelsTestnet[i].feePerKB) + ' ' + unitName; } } - return cb({ + return cb(null, { 'livenet': levelsLivenet, 'testnet': levelsTestnet }); diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js index 0d6977173..cdcb501d7 100644 --- a/src/js/services/onGoingProcess.js +++ b/src/js/services/onGoingProcess.js @@ -25,7 +25,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti 'recreating': gettext('Recreating Wallet...'), 'rejectTx': gettext('Rejecting payment proposal'), 'removeTx': gettext('Deleting payment proposal'), - 'retrivingInputs': gettext('Retrieving inputs information'), + 'retrievingInputs': gettext('Retrieving inputs information'), 'scanning': gettext('Scanning Wallet funds...'), 'sendingTx': gettext('Sending transaction'), 'signingTx': gettext('Signing transaction'), diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index b00722c76..773c8542e 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -562,20 +562,13 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim if (lodash.isEmpty(txp) || lodash.isEmpty(wallet)) return cb('MISSING_PARAMETER'); - if (txp.sendMax) { - wallet.createTxProposal(txp, function(err, createdTxp) { - if (err) return cb(err); - else return cb(null, createdTxp); - }); - } else { - wallet.createTxProposal(txp, function(err, createdTxp) { - if (err) return cb(err); - else { - $log.debug('Transaction created'); - return cb(null, createdTxp); - } - }); - } + wallet.createTxProposal(txp, function(err, createdTxp) { + if (err) return cb(err); + else { + $log.debug('Transaction created'); + return cb(null, createdTxp); + } + }); }; root.publishTx = function(wallet, txp, cb) { @@ -1083,6 +1076,12 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim return type; }; + root.getSendMaxInfo = function(wallet, opts, cb) { + opts = opts || {}; + wallet.getSendMaxInfo(opts, function(err, res) { + return cb(err, res); + }); + }; return root; }); diff --git a/src/sass/views/tab-send.scss b/src/sass/views/tab-send.scss index 4821d2570..92042b2c9 100644 --- a/src/sass/views/tab-send.scss +++ b/src/sass/views/tab-send.scss @@ -1,17 +1,32 @@ #tab-send { @extend .deflash-blue; - .qr-scan-icon a { - z-index: 10; - display: block; - position: absolute; - top: 55px; - right: 0; - padding: 0 10px; - font-size: 24px; + .input { + input { + width: 100%; + height: auto; + } + &.item { + height: 55px; + } + i { + &.left { + padding-left: 15px; + } + &.qr { + cursor: pointer; + cursor: hand; + padding-right: 5px; + } + } + } + .qr-scan-icon { cursor: pointer; + cursor: hand; + border-left: 1px solid rgb(228, 228, 228); + padding-left: 10px; } .qr-icon { - line-height: 45px; + line-height: 20px; } .zero-state-cta { padding-bottom: 3vh; diff --git a/www/img/scan-ico.svg b/www/img/scan-ico.svg new file mode 100644 index 000000000..5d13c91fe --- /dev/null +++ b/www/img/scan-ico.svg @@ -0,0 +1,24 @@ + + + + scan-ico + Created with Sketch. + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/views/amount.html b/www/views/amount.html index 6892406a7..cfdfb9373 100644 --- a/www/views/amount.html +++ b/www/views/amount.html @@ -5,6 +5,11 @@ + + + diff --git a/www/views/confirm.html b/www/views/confirm.html index 85d9006d4..5f5ebae63 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -7,16 +7,17 @@ - +
- Sending + Sending + Sending maximum amount
-
{{displayAmount}} {{displayUnit}}
-
{{alternativeAmountStr}}
+
{{displayAmount || '...'}} {{displayUnit}}
+
{{alternativeAmountStr || '...'}}
@@ -49,13 +50,7 @@ Multiple recipients -->
-
- No wallets available -
-
- Insufficient funds -
- + From
@@ -65,30 +60,36 @@
- + Add Memo {{description}} -
+
Fee: {{feeLevel}} {{fee || '...'}}
+
+ No wallets available +
+
+ Insufficient funds +
Click to pay Slide to pay diff --git a/www/views/tab-send.html b/www/views/tab-send.html index c4751bdf9..805eb616d 100644 --- a/www/views/tab-send.html +++ b/www/views/tab-send.html @@ -18,19 +18,15 @@ -
+
Recipient
-
- -
- - - -
+ +
+ + +
+
Contacts