Merge pull request #1228 from eordano/feature/fiat
Allow user to select an alternative currency and specify amount of money in a fiat currency
This commit is contained in:
commit
e73a3f8160
13 changed files with 288 additions and 24 deletions
|
|
@ -2,14 +2,67 @@
|
|||
var bitcore = require('bitcore');
|
||||
|
||||
angular.module('copayApp.controllers').controller('SendController',
|
||||
function($scope, $rootScope, $window, $timeout, $anchorScroll, $modal, isMobile, notification, controllerUtils) {
|
||||
function($scope, $rootScope, $window, $timeout, $anchorScroll, $modal, isMobile, notification, controllerUtils, rateService) {
|
||||
$scope.title = 'Send';
|
||||
$scope.loading = false;
|
||||
var satToUnit = 1 / config.unitToSatoshi;
|
||||
$scope.defaultFee = bitcore.TransactionBuilder.FEE_PER_1000B_SAT * satToUnit;
|
||||
$scope.unitToBtc = config.unitToSatoshi / bitcore.util.COIN;
|
||||
$scope.unitToSatoshi = config.unitToSatoshi;
|
||||
$scope.minAmount = config.limits.minAmountSatoshi * satToUnit;
|
||||
|
||||
$scope.alternativeName = config.alternativeName;
|
||||
$scope.alternativeIsoCode = config.alternativeIsoCode;
|
||||
|
||||
$scope.isRateAvailable = false;
|
||||
$scope.rateService = rateService;
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
$scope.isRateAvailable = true;
|
||||
$scope.$digest();
|
||||
});
|
||||
|
||||
/**
|
||||
* Setting the two related amounts as properties prevents an infinite
|
||||
* recursion for watches while preserving the original angular updates
|
||||
*/
|
||||
Object.defineProperty($scope,
|
||||
"alternative", {
|
||||
get: function () {
|
||||
return this._alternative;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this._alternative = newValue;
|
||||
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
|
||||
this._amount = Number.parseFloat(
|
||||
(rateService.fromFiat(newValue, config.alternativeIsoCode) * satToUnit
|
||||
).toFixed(config.unitDecimals), 10);
|
||||
} else {
|
||||
this._amount = 0;
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty($scope,
|
||||
"amount", {
|
||||
get: function () {
|
||||
return this._amount;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this._amount = newValue;
|
||||
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
|
||||
this._alternative = Number.parseFloat(
|
||||
(rateService.toFiat(newValue * config.unitToSatoshi, config.alternativeIsoCode)
|
||||
).toFixed(2), 10);
|
||||
} else {
|
||||
this._alternative = 0;
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
$scope.loadTxs = function() {
|
||||
var opts = {
|
||||
pending: true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('SettingsController', function($scope, $rootScope, $window, $location, controllerUtils) {
|
||||
angular.module('copayApp.controllers').controller('SettingsController', function($scope, $rootScope, $window, $location, controllerUtils, rateService) {
|
||||
|
||||
controllerUtils.redirIfLogged();
|
||||
$scope.title = 'Settings';
|
||||
|
|
@ -14,21 +14,41 @@ angular.module('copayApp.controllers').controller('SettingsController', function
|
|||
$scope.unitOpts = [{
|
||||
name: 'Satoshis (100,000,000 satoshis = 1BTC)',
|
||||
shortName: 'SAT',
|
||||
value: 1
|
||||
value: 1,
|
||||
decimals: 0
|
||||
}, {
|
||||
name: 'bits (1,000,000 bits = 1BTC)',
|
||||
shortName: 'bits',
|
||||
value: 100
|
||||
value: 100,
|
||||
decimals: 2
|
||||
}, {
|
||||
name: 'mBTC (1,000 mBTC = 1BTC)',
|
||||
shortName: 'mBTC',
|
||||
value: 100000
|
||||
value: 100000,
|
||||
decimals: 5
|
||||
}, {
|
||||
name: 'BTC',
|
||||
shortName: 'BTC',
|
||||
value: 100000000
|
||||
value: 100000000,
|
||||
decimals: 8
|
||||
}];
|
||||
|
||||
$scope.selectedAlternative = {
|
||||
name: config.alternativeName,
|
||||
isoCode: config.alternativeIsoCode
|
||||
};
|
||||
$scope.alternativeOpts = rateService.isAvailable ?
|
||||
rateService.listAlternatives() : [$scope.selectedAlternative];
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
$scope.alternativeOpts = rateService.listAlternatives();
|
||||
for (var ii in $scope.alternativeOpts) {
|
||||
if (config.alternativeIsoCode === $scope.alternativeOpts[ii].isoCode) {
|
||||
$scope.selectedAlternative = $scope.alternativeOpts[ii];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (var ii in $scope.unitOpts) {
|
||||
if (config.unitName === $scope.unitOpts[ii].shortName) {
|
||||
$scope.selectedUnit = $scope.unitOpts[ii];
|
||||
|
|
@ -68,7 +88,11 @@ angular.module('copayApp.controllers').controller('SettingsController', function
|
|||
disableVideo: $scope.disableVideo,
|
||||
unitName: $scope.selectedUnit.shortName,
|
||||
unitToSatoshi: $scope.selectedUnit.value,
|
||||
version: copay.version,
|
||||
unitDecimals: $scope.selectedUnit.decimals,
|
||||
alternativeName: $scope.selectedAlternative.name,
|
||||
alternativeIsoCode: $scope.selectedAlternative.isoCode,
|
||||
|
||||
version: copay.version
|
||||
}));
|
||||
|
||||
// Go home reloading the application
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
var bitcore = require('bitcore');
|
||||
|
||||
angular.module('copayApp.services')
|
||||
.factory('controllerUtils', function($rootScope, $sce, $location, notification, $timeout, video, uriHandler) {
|
||||
.factory('controllerUtils', function($rootScope, $sce, $location, notification, $timeout, video, uriHandler, rateService) {
|
||||
var root = {};
|
||||
root.getVideoMutedStatus = function(copayer) {
|
||||
if (!$rootScope.videoInfo) return;
|
||||
|
|
@ -217,7 +217,15 @@ angular.module('copayApp.services')
|
|||
$rootScope.balanceByAddr = balanceByAddr;
|
||||
root.updateAddressList();
|
||||
$rootScope.updatingBalance = false;
|
||||
return cb ? cb() : null;
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
$rootScope.totalBalanceAlternative = rateService.toFiat(balanceSat, config.alternativeIsoCode);
|
||||
$rootScope.alternativeIsoCode = config.alternativeIsoCode;
|
||||
$rootScope.lockedBalanceAlternative = rateService.toFiat(balanceSat - safeBalanceSat, config.alternativeIsoCode);
|
||||
|
||||
|
||||
return cb ? cb() : null;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
83
js/services/rate.js
Normal file
83
js/services/rate.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
'use strict';
|
||||
|
||||
var RateService = function(request) {
|
||||
this.isAvailable = false;
|
||||
this.UNAVAILABLE_ERROR = 'Service is not available - check for service.isAvailable or use service.whenAvailable';
|
||||
this.SAT_TO_BTC = 1 / 1e8;
|
||||
var MINS_IN_HOUR = 60;
|
||||
var MILLIS_IN_SECOND = 1000;
|
||||
var rateServiceConfig = config.rate;
|
||||
var updateFrequencySeconds = rateServiceConfig.updateFrequencySeconds || 60 * MINS_IN_HOUR;
|
||||
var rateServiceUrl = rateServiceConfig.url || 'https://bitpay.com/api/rates';
|
||||
this.queued = [];
|
||||
this.alternatives = [];
|
||||
var that = this;
|
||||
var backoffSeconds = 5;
|
||||
var retrieve = function() {
|
||||
request.get({
|
||||
url: rateServiceUrl,
|
||||
json: true
|
||||
}, function(err, response, listOfCurrencies) {
|
||||
if (err) {
|
||||
backoffSeconds *= 1.5;
|
||||
setTimeout(retrieve, backoffSeconds * MILLIS_IN_SECOND);
|
||||
return;
|
||||
}
|
||||
var rates = {};
|
||||
listOfCurrencies.forEach(function(element) {
|
||||
rates[element.code] = element.rate;
|
||||
that.alternatives.push({
|
||||
name: element.name,
|
||||
isoCode: element.code,
|
||||
rate: element.rate
|
||||
});
|
||||
});
|
||||
that.isAvailable = true;
|
||||
that.rates = rates;
|
||||
that.queued.forEach(function(callback) {
|
||||
setTimeout(callback, 1);
|
||||
});
|
||||
setTimeout(retrieve, updateFrequencySeconds * MILLIS_IN_SECOND);
|
||||
});
|
||||
};
|
||||
retrieve();
|
||||
};
|
||||
|
||||
RateService.prototype.whenAvailable = function(callback) {
|
||||
if (this.isAvailable) {
|
||||
setTimeout(callback, 1);
|
||||
} else {
|
||||
this.queued.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
RateService.prototype.toFiat = function(satoshis, code) {
|
||||
if (!this.isAvailable) {
|
||||
throw new Error(this.UNAVAILABLE_ERROR);
|
||||
}
|
||||
return satoshis * this.SAT_TO_BTC * this.rates[code];
|
||||
};
|
||||
|
||||
RateService.prototype.fromFiat = function(amount, code) {
|
||||
if (!this.isAvailable) {
|
||||
throw new Error(this.UNAVAILABLE_ERROR);
|
||||
}
|
||||
return amount / this.rates[code] / this.SAT_TO_BTC;
|
||||
};
|
||||
|
||||
RateService.prototype.listAlternatives = function() {
|
||||
if (!this.isAvailable) {
|
||||
throw new Error(this.UNAVAILABLE_ERROR);
|
||||
}
|
||||
|
||||
var alts = [];
|
||||
this.alternatives.forEach(function(element) {
|
||||
alts.push({
|
||||
name: element.name,
|
||||
isoCode: element.isoCode
|
||||
});
|
||||
});
|
||||
return alts;
|
||||
};
|
||||
|
||||
angular.module('copayApp.services').service('rateService', RateService);
|
||||
6
js/services/request.js
Normal file
6
js/services/request.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('request', function() {
|
||||
return require('request');
|
||||
});
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue