diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 1f354fd4d..eff5aa4b2 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -570,7 +570,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( if (usingCustomFee) { scope.customFeePerKB = tx.feeRate; - scope.feePerSatByte = (tx.feeRate / 1000).toFixed(); + scope.feePerSatByte = tx.feeRate / 1000; } $ionicModal.fromTemplateUrl('views/modals/chooseFeeLevel.html', { diff --git a/src/js/controllers/modals/feeLevels.js b/src/js/controllers/modals/feeLevels.js new file mode 100644 index 000000000..9006fcd01 --- /dev/null +++ b/src/js/controllers/modals/feeLevels.js @@ -0,0 +1,120 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('feeLevelsController', function($scope, $timeout, $log, lodash, gettextCatalog, configService, feeService, ongoingProcess, popupService) { + + var FEE_MULTIPLIER = 10; + var FEE_MIN = 0; + var FEE_MAX = 1000000; + + var showErrorAndClose = function(title, msg) { + title = title || gettextCatalog.getString('Error'); + $log.error(msg); + popupService.showAlert(title, msg, function() { + $scope.chooseFeeLevelModal.hide(); + }); + + }; + + var getMinRecommended = function() { + var value = lodash.find($scope.feeLevels[$scope.network], { + level: 'superEconomy' + }); + return parseInt((value.feePerKB / 1000).toFixed()); + }; + + var getMaxRecommended = function() { + var value = lodash.find($scope.feeLevels[$scope.network], { + level: 'urgent' + }); + return parseInt((value.feePerKB / 1000).toFixed()); + }; + + $scope.ok = function() { + $scope.customFeePerKB = $scope.customFeePerKB ? ($scope.customSatPerByte.value * 1000).toFixed() : null; + $scope.hideModal($scope.feeLevel, $scope.customFeePerKB); + }; + + $scope.setFeesRecommended = function() { + $scope.minFeeAllowed = FEE_MIN; + $scope.maxFeeAllowed = FEE_MAX; + $scope.maxFeeRecommended = getMaxRecommended() * FEE_MULTIPLIER; + $scope.minFeeRecommended = getMinRecommended(); + }; + + $scope.checkFees = function(feePerSatByte) { + var fee = Number(feePerSatByte); + + if (fee <= $scope.minFeeAllowed) $scope.showError = true; + else $scope.showError = false; + + if (fee > $scope.minFeeAllowed && fee < $scope.minFeeRecommended) $scope.showMinWarning = true; + else $scope.showMinWarning = false; + + if (fee < $scope.maxFeeAllowed && fee > $scope.maxFeeRecommended) $scope.showMaxWarning = true; + else $scope.showMaxWarning = false; + }; + + $scope.updateFeeRate = function() { + var value = lodash.find($scope.feeLevels[$scope.network], { + level: $scope.feeLevel + }); + + // If no custom fee + if (value) { + $scope.customFeePerKB = null; + $scope.feePerSatByte = (value.feePerKB / 1000).toFixed(); + $scope.avgConfirmationTime = value.nbBlocks * 10; + } else { + $scope.avgConfirmationTime = null; + $scope.customSatPerByte = { value: Number($scope.feePerSatByte) }; + $scope.customFeePerKB = ($scope.feePerSatByte * 1000).toFixed(); + } + + // Warnings + $scope.setFeesRecommended(); + $scope.checkFees($scope.feePerSatByte); + + $timeout(function() { + $scope.$apply(); + }); + }; + + $scope.$watch( + "selectedFee.value", + function ( newValue, oldValue ) { + if (newValue != oldValue) { + $log.debug('New fee level: ' + newValue); + $scope.feeLevel = $scope.selectedFee.value; + $scope.updateFeeRate(); + } + } + ); + + // From parent controller + // $scope.network + // $scope.feeLevel + // + // IF usingCustomFee + // $scope.customFeePerKB + // $scope.feePerSatByte + + if (lodash.isEmpty($scope.feeLevel)) showErrorAndClose(null, gettextCatalog.getString('Fee level is not defined') ); + $scope.selectedFee = { value: $scope.feeLevel }; + + $scope.feeOpts = feeService.feeOpts; + $scope.loadingFee = true; + feeService.getFeeLevels(function(err, levels) { + $scope.loadingFee = false; + if (err || lodash.isEmpty(levels)) { + showErrorAndClose(null, err); + return; + } + if (lodash.isEmpty(levels)) { + showErrorAndClose(null, gettextCatalog.getString('Could not get fee levels')); + return; + } + $scope.feeLevels = levels; + $scope.updateFeeRate(); + }); + +}); diff --git a/src/sass/views/includes/modals/choose-fee-level.scss b/src/sass/views/includes/modals/choose-fee-level.scss new file mode 100644 index 000000000..c37e9b505 --- /dev/null +++ b/src/sass/views/includes/modals/choose-fee-level.scss @@ -0,0 +1,63 @@ +#choose-fee-level { + @extend .deflash-blue; + .selected-fee-level { + text-align: center; + background: #f9f9f9; + font-size: 11px; + height: 120px; + padding-top: 25px; + .row { + padding: 0; + } + .separator { + border-left: 1px solid #d9d9df; + height: 75%; + } + .value { + font-size: 20px; + margin-bottom: 10px; + } + .rate .list { + margin-bottom: 0; + } + + .item-input { + input[type="number"] { + text-align: right; + padding-right: 90px; + } + .unit { + color: #9c9c9c; + background: #f2f2f2; + position: absolute; + right: 0; + top: 0; + padding: 15px 10px 12px 10px; + } + } + } + .warning-fee { + padding: 5px 10px; + color: $v-warning-color; + font-size: 12px; + text-align: center; + i { + margin-right: 8px; + } + } + .error-fee { + padding: 5px 10px; + color: $v-error-color; + font-size: 12px; + text-align: center; + i { + margin-right: 8px; + } + } + .box-notification { + margin: 0; + padding: 1px; + text-align: center; + } + +} diff --git a/src/sass/views/views.scss b/src/sass/views/views.scss index 7a8058339..cbae9b19f 100644 --- a/src/sass/views/views.scss +++ b/src/sass/views/views.scss @@ -34,6 +34,7 @@ @import "includes/walletActivity"; @import "includes/wallets"; @import "includes/modals/modals"; +@import "includes/modals/choose-fee-level"; @import "includes/clickToAccept"; @import "includes/incomingDataMenu"; @import "includes/slideToAccept"; diff --git a/www/views/modals/chooseFeeLevel.html b/www/views/modals/chooseFeeLevel.html index b2877c979..851cb3096 100644 --- a/www/views/modals/chooseFeeLevel.html +++ b/www/views/modals/chooseFeeLevel.html @@ -1,41 +1,82 @@ - +
{{'Bitcoin Network Fee Policy'|translate}}
-
- -
-
-
- Average confirmation time: - {{avgConfirmationTime | amDurationFormat: 'minute'}} - Could not be estimated - ... + +
+ Testnet +
+
+
+
+ + {{avgConfirmationTime | amDurationFormat: 'minute'}} + + ...
-
- Current fee rate for this policy: - {{feePerSatByte}} satoshis/byte - ... + Average confirmation time +
+
+
+
+ + {{feePerSatByte}} sat/byte + + ... +
+ Current fee rate for this policy +
+
+
+ +
+
+ + + Transactions without fee are not supported. + +
+
+ + + Your fee is lower than recommended. + + + You should not set a fee higher than {{maxFeeRecommended}} satoshis/byte. + +
- [{{network}}]
-
- - {{level|translate}} - -
-
- - Your fee is lower than recommended super economy fee ({{getMinimumRecommeded()}} satoshis/byte). The transaction may never get confirmed. -
-
- - You could not set a fee higher than 1000 satoshis/byte. + +
+
+