Merge pull request #6432 from cmgustavo/ref/custom-fee-02

Ref/custom fee 02
This commit is contained in:
Matias Alejo Garcia 2017-07-18 19:13:54 +02:00 committed by GitHub
commit 5ca3dc3cd2
5 changed files with 253 additions and 28 deletions

View file

@ -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', {

View file

@ -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();
});
});

View file

@ -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;
}
}

View file

@ -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";

View file

@ -1,41 +1,82 @@
<ion-modal-view id="settings-fee" class="settings" ng-controller="preferencesFeeController">
<ion-modal-view id="choose-fee-level" ng-controller="feeLevelsController">
<ion-header-bar align-title="center" class="bar-royal">
<div class="title">
{{'Bitcoin Network Fee Policy'|translate}}
</div>
<button ng-disabled="invalidCustomFeeEntered" class="button button-clear" ng-click="chooseNewFee()">
<button
ng-disabled="customFeePerKB && !customSatPerByte.value"
class="button button-clear" ng-click="ok()" translate>
OK
</button>
</ion-header-bar>
<ion-content ng-init="init()">
<div class="settings-explanation">
<div class="estimates">
<div>
<span translate>Average confirmation time</span>:
<span class="fee-minutes" ng-if="avgConfirmationTime && currentFeeLevel != 'custom'">{{avgConfirmationTime | amDurationFormat: 'minute'}}</span>
<span class="fee-minutes" ng-if="currentFeeLevel == 'custom' && !invalidCustomFeeEntered && !loadingFee" translate>Could not be estimated</span>
<span ng-if="loadingFee || invalidCustomFeeEntered">...</span>
<ion-content>
<div class="box-notification warning" ng-if="network!='livenet'">
Testnet
</div>
<div class="row selected-fee-level" ng-show="feeLevel">
<div class="col time" ng-if="!customFeePerKB">
<div class="value">
<span ng-if="avgConfirmationTime">
{{avgConfirmationTime | amDurationFormat: 'minute'}}
</span>
<span ng-if="loadingFee">...</span>
</div>
<div>
<span translate>Current fee rate for this policy</span>:
<span class="fee-rate" ng-if="feePerSatByte && !invalidCustomFeeEntered && !loadingFee">{{feePerSatByte}} satoshis/byte</span>
<span ng-if="loadingFee || invalidCustomFeeEntered">...</span>
<span translate>Average confirmation time</span>
</div>
<div class="col rate" ng-class="{'separator': !customFeePerKB}">
<div ng-if="!customFeePerKB">
<div class="value">
<span ng-if="feePerSatByte && !loadingFee">
{{feePerSatByte}} sat/byte
</span>
<span ng-if="loadingFee">...</span>
</div>
<span translate>Current fee rate for this policy</span>
</div>
<div ng-if="customFeePerKB">
<div class="list">
<label class="item item-input">
<input
type="number"
placeholder="{{'Enter custom fee'|translate}}"
ng-min="minFeeAllowed"
ng-max="maxFeeAllowed"
min="minFeeRecommended"
max="maxFeeRecommended"
ng-change="checkFees(customSatPerByte.value)"
ng-model="customSatPerByte.value"
ng-required="customFeePerKB">
<span class="unit">sat/byte</span>
</label>
</div>
<div class="error-fee" ng-if="showError">
<i class="icon ion-close-circled"></i>
<span translate>
Transactions without fee are not supported.
</span>
</div>
<div class="warning-fee" ng-if="showMinWarning || showMaxWarning">
<i class="icon ion-alert-circled"></i>
<span ng-if="showMinWarning" translate>
Your fee is lower than recommended.
</span>
<span ng-if="showMaxWarning" translate>
You should not set a fee higher than {{maxFeeRecommended}} satoshis/byte.
</span>
</div>
</div>
<span ng-if="network!='livenet'">[{{network}}]</span>
</div>
</div>
<div class="fee-policies">
<ion-radio ng-repeat="(fee, level) in feeOpts" ng-value="fee" ng-model="currentFeeLevel" ng-click="save(fee)">
{{level|translate}}
</ion-radio>
</div>
<div class="comment" ng-if="showMinWarning">
<i class="icon"><img src="img/icon-warning.png"></i>
<span class="text" translate>Your fee is lower than recommended super economy fee ({{getMinimumRecommeded()}} satoshis/byte). The transaction may never get confirmed.</span>
</div>
<div class="comment" ng-if="showMaxWarning">
<i class="icon"><img src="img/icon-warning.png"></i>
<span class="text" translate>You could not set a fee higher than 1000 satoshis/byte.</span>
<div class="list" ng-show="feeLevel">
<label class="item item-input item-select">
<div class="input-label" translate>
Fee level
</div>
<select ng-options="fee as level for (fee,level) in feeOpts" ng-model="selectedFee.value">
</select>
</label>
</div>
</ion-content>
</ion-modal-view>