Merge branch 'wallet/sprint/21' into wallet/task/546
This commit is contained in:
commit
7a78eb1261
70 changed files with 3660 additions and 1001 deletions
|
|
@ -1,16 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('amountController', amountController);
|
||||
(function(){
|
||||
|
||||
function amountController(configService, $filter, gettextCatalog, $ionicModal, $ionicScrollDelegate, lodash, $log, nodeWebkitService, rateService, $scope, $state, $timeout, sendFlowService, shapeshiftService, txFormatService, platformInfo, profileService, walletService, $window, ongoingProcess, popupService) {
|
||||
angular
|
||||
.module('bitcoincom.controllers')
|
||||
.controller('amountController', amountController);
|
||||
|
||||
function amountController(configService, $filter, gettextCatalog, $ionicHistory, $ionicModal, $ionicScrollDelegate, lodash, $log, nodeWebkitService, rateService, $scope, $state, $timeout, sendFlowService, shapeshiftService, txFormatService, platformInfo, ongoingProcess, popupService, profileService, walletService, $window) {
|
||||
var vm = this;
|
||||
|
||||
// Variables
|
||||
vm.allowSend = false;
|
||||
vm.altCurrencyList = [];
|
||||
vm.alternativeAmount = '';
|
||||
vm.alternativeUnit = '';
|
||||
vm.amount = '0';
|
||||
vm.availableFunds = '';
|
||||
vm.canSendAllAvailableFunds = true;
|
||||
vm.errorMessage = '';
|
||||
// Use insufficient for logic, as when the amount is invalid, funds being
|
||||
// either sufficent or insufficient doesn't make sense.
|
||||
vm.fundsAreInsufficient = false;
|
||||
|
|
@ -20,9 +27,13 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
vm.lastUsedPopularList = [];
|
||||
vm.maxAmount = 0;
|
||||
vm.minAmount = 0;
|
||||
vm.sendableFunds = '';
|
||||
vm.showSendMaxButton = false;
|
||||
vm.showSendLimitMaxButton = false;
|
||||
vm.thirdParty = false;
|
||||
vm.unit = '';
|
||||
|
||||
// Functions
|
||||
vm.changeUnit = changeUnit;
|
||||
vm.close = close;
|
||||
vm.findCurrency = findCurrency;
|
||||
|
|
@ -35,7 +46,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
vm.removeDigit = removeDigit;
|
||||
vm.save = save;
|
||||
vm.sendMax = sendMax;
|
||||
vm.errorMessage = '';
|
||||
|
||||
|
||||
$scope.$on('$ionicView.beforeEnter', onBeforeEnter);
|
||||
$scope.$on('$ionicView.leave', onLeave);
|
||||
|
|
@ -46,10 +57,8 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
|
||||
var altCurrencyModal = null;
|
||||
var altUnitIndex = 0;
|
||||
var availableFundsInCrypto = '';
|
||||
var availableFundsInFiat = '';
|
||||
var availableSatoshis = null;
|
||||
var availableUnits = [];
|
||||
var canSendMax = true;
|
||||
var fiatCode;
|
||||
var isNW = platformInfo.isNW;
|
||||
var isAndroid = platformInfo.isAndroid;
|
||||
|
|
@ -57,10 +66,18 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
var lastUsedAltCurrencyList = [];
|
||||
var passthroughParams = {};
|
||||
var satToUnit;
|
||||
var transactionSendableAmount = {
|
||||
crypto: '',
|
||||
satoshis: null
|
||||
};
|
||||
var unitDecimals;
|
||||
var unitIndex = 0;
|
||||
var unitToSatoshi;
|
||||
var useSendMax = false;
|
||||
var walletSpendableAmount = {
|
||||
crypto: '',
|
||||
satoshis: null
|
||||
};
|
||||
|
||||
function onLeave() {
|
||||
angular.element($window).off('keydown');
|
||||
|
|
@ -81,40 +98,13 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
vm.minAmount = parseFloat(passthroughParams.minAmount);
|
||||
vm.maxAmount = parseFloat(passthroughParams.maxAmount);
|
||||
|
||||
if (passthroughParams.thirdParty) {
|
||||
vm.thirdParty = passthroughParams.thirdParty; // Parse stringified JSON-object
|
||||
if (vm.thirdParty) {
|
||||
if (vm.thirdParty.id === 'shapeshift') {
|
||||
if (!vm.thirdParty.data) {
|
||||
vm.thirdParty.data = {};
|
||||
}
|
||||
vm.thirdParty.data['fromWalletId'] = vm.fromWalletId;
|
||||
|
||||
vm.fromWallet = profileService.getWallet(vm.fromWalletId);
|
||||
vm.toWallet = profileService.getWallet(vm.toWalletId);
|
||||
|
||||
ongoingProcess.set('connectingShapeshift', true);
|
||||
shapeshiftService.getMarketData(vm.fromWallet.coin, vm.toWallet.coin, function(err, data) {
|
||||
|
||||
if (err) {
|
||||
// Error stop here
|
||||
ongoingProcess.set('connectingShapeshift', false);
|
||||
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () {
|
||||
$ionicHistory.goBack();
|
||||
});
|
||||
} else {
|
||||
vm.thirdParty.data['minAmount'] = vm.minAmount = parseFloat(data.minimum);
|
||||
vm.thirdParty.data['maxAmount'] = vm.maxAmount = parseFloat(data.maxLimit);
|
||||
ongoingProcess.set('connectingShapeshift', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm.isRequestingSpecificAmount = !passthroughParams.fromWalletId;
|
||||
vm.showSendMaxButton = !vm.isRequestingSpecificAmount;
|
||||
|
||||
var config = configService.getSync().wallet.settings;
|
||||
unitToSatoshi = config.unitToSatoshi;
|
||||
satToUnit = 1 / unitToSatoshi;
|
||||
unitDecimals = config.unitDecimals;
|
||||
|
||||
setAvailableUnits();
|
||||
updateUnitUI();
|
||||
|
|
@ -146,10 +136,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
});
|
||||
}
|
||||
|
||||
unitToSatoshi = config.unitToSatoshi;
|
||||
satToUnit = 1 / unitToSatoshi;
|
||||
unitDecimals = config.unitDecimals;
|
||||
|
||||
|
||||
resetAmount();
|
||||
|
||||
processAmount();
|
||||
|
|
@ -221,6 +208,13 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
var fromWallet = profileService.getWallet(passthroughParams.fromWalletId);
|
||||
updateAvailableFundsFromWallet(fromWallet);
|
||||
}
|
||||
|
||||
if (passthroughParams.thirdParty) {
|
||||
vm.thirdParty = passthroughParams.thirdParty; // Parse stringified JSON-object
|
||||
if (vm.thirdParty) {
|
||||
initShapeshift();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -228,6 +222,34 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
sendFlowService.router.goBack();
|
||||
}
|
||||
|
||||
function initShapeshift() {
|
||||
if (vm.thirdParty.id === 'shapeshift') {
|
||||
vm.thirdParty.data = vm.thirdParty.data || {};
|
||||
|
||||
vm.fromWallet = profileService.getWallet(vm.fromWalletId);
|
||||
vm.toWallet = profileService.getWallet(vm.toWalletId);
|
||||
|
||||
vm.showSendMaxButton = false;
|
||||
vm.showSendLimitMaxButton = false;
|
||||
vm.canSendAllAvailableFunds = false;
|
||||
|
||||
ongoingProcess.set('connectingShapeshift', true);
|
||||
shapeshiftService.getMarketData(vm.fromWallet.coin, vm.toWallet.coin, function onMarketData(err, data) {
|
||||
ongoingProcess.set('connectingShapeshift', false);
|
||||
if (err) {
|
||||
// Error stop here
|
||||
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.message, function () {
|
||||
goBack();
|
||||
});
|
||||
} else {
|
||||
vm.thirdParty.data.minAmount = vm.minAmount = parseFloat(data.minimum);
|
||||
vm.thirdParty.data.maxAmount = vm.maxAmount = parseFloat(data.maxLimit);
|
||||
setMaximumButtonFromWallet(vm.fromWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function paste(value) {
|
||||
vm.amount = value;
|
||||
processAmount();
|
||||
|
|
@ -243,8 +265,28 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
}
|
||||
|
||||
function sendMax() {
|
||||
useSendMax = true;
|
||||
finish();
|
||||
if (canSendMax) {
|
||||
useSendMax = true;
|
||||
finish();
|
||||
} else {
|
||||
var transactionSendableAmountInUnits = transactionSendableAmount.satoshis * satToUnit;
|
||||
if (vm.minAmount && transactionSendableAmountInUnits < vm.minAmount) {
|
||||
popupService.showAlert(
|
||||
gettextCatalog.getString('Insufficient funds'),
|
||||
gettextCatalog.getString('Amount below minimum allowed')
|
||||
);
|
||||
} else {
|
||||
// Need to be precise, so use crypto directly rather than fiat with exchange rate
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
var tempIndex = altUnitIndex;
|
||||
altUnitIndex = unitIndex;
|
||||
unitIndex = tempIndex;
|
||||
}
|
||||
vm.amount = transactionSendableAmountInUnits.toFixed(LENGTH_AFTER_COMMA_EXPRESSION_LIMIT);
|
||||
useSendMax = true;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateUnitUI() {
|
||||
|
|
@ -364,8 +406,8 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
amountInCrypto = a;
|
||||
var amountInSatoshis = a * unitToSatoshi;
|
||||
vm.fundsAreInsufficient = !!passthroughParams.fromWalletId
|
||||
&& availableSatoshis !== null
|
||||
&& availableSatoshis < amountInSatoshis;
|
||||
&& walletSpendableAmount.satoshis !== null
|
||||
&& walletSpendableAmount.satoshis < amountInSatoshis;
|
||||
|
||||
vm.alternativeAmount = txFormatService.formatAmount(amountInSatoshis, true);
|
||||
vm.allowSend = lodash.isNumber(a)
|
||||
|
|
@ -385,8 +427,8 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
} else {
|
||||
amountInCrypto = result;
|
||||
vm.fundsAreInsufficient = passthroughParams.fromWalletId
|
||||
&& availableSatoshis !== null
|
||||
&& availableSatoshis < result * unitToSatoshi;
|
||||
&& walletSpendableAmount.satoshis !== null
|
||||
&& walletSpendableAmount.satoshis < result * unitToSatoshi;
|
||||
|
||||
vm.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
|
||||
vm.allowSend = lodash.isNumber(result)
|
||||
|
|
@ -460,13 +502,13 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
|
||||
var satoshis = 0;
|
||||
if (unit.isFiat) {
|
||||
satoshis = (fromFiat(uiAmount) * unitToSatoshi).toFixed(0);
|
||||
satoshis = Math.floor(fromFiat(uiAmount) * unitToSatoshi);
|
||||
} else {
|
||||
satoshis = (uiAmount * unitToSatoshi).toFixed(0);
|
||||
satoshis = Math.floor(uiAmount * unitToSatoshi);
|
||||
}
|
||||
|
||||
var confirmData = {
|
||||
amount: useSendMax ? undefined : satoshis,
|
||||
amount: (useSendMax && canSendMax) ? undefined : satoshis,
|
||||
displayAddress: passthroughParams.displayAddress,
|
||||
fromWalletId: passthroughParams.fromWalletId,
|
||||
sendMax: useSendMax,
|
||||
|
|
@ -482,7 +524,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
$state.transitionTo('tabs.paymentRequest.confirm', confirmData);
|
||||
} else {
|
||||
sendFlowService.goNext(confirmData);
|
||||
$scope.useSendMax = null;
|
||||
useSendMax = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -600,18 +642,73 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
}
|
||||
|
||||
function updateAvailableFundsStringIfNeeded() {
|
||||
if (passthroughParams.fromWalletId && availableSatoshis !== null) {
|
||||
availableFundsInFiat = '';
|
||||
vm.availableFunds = availableFundsInCrypto;
|
||||
if (passthroughParams.fromWalletId && walletSpendableAmount.satoshis !== null) {
|
||||
vm.availableFunds = walletSpendableAmount.crypto;
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
var coin = availableUnits[altUnitIndex].id;
|
||||
txFormatService.formatAlternativeStr(coin, availableSatoshis, function formatCallback(formatted){
|
||||
if (formatted) {
|
||||
availableFundsInFiat = formatted;
|
||||
txFormatService.formatAlternativeStr(coin, walletSpendableAmount.satoshis, function formatCallback(formatted){
|
||||
|
||||
if (formatted) {
|
||||
$scope.$apply(function() {
|
||||
vm.availableFunds = availableFundsInFiat;
|
||||
vm.availableFunds = formatted;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
updateMaximumButtonIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function updateAvailableFundsFromWallet(wallet) {
|
||||
console.log('amount updateAvailableFundsFromWallet()');
|
||||
var availableFundsInFiat = '';
|
||||
if (wallet.status && wallet.status.isValid) {
|
||||
walletSpendableAmount.crypto = wallet.status.spendableBalanceStr;
|
||||
walletSpendableAmount.satoshis = wallet.status.spendableAmount;
|
||||
if (wallet.status.alternativeBalanceAvailable) {
|
||||
availableFundsInFiat = wallet.status.spendableBalanceAlternative + ' ' + wallet.status.alternativeIsoCode;
|
||||
} else {
|
||||
availableFundsInFiat = '';
|
||||
}
|
||||
|
||||
} else if (wallet.cachedStatus && wallet.cachedStatus.isValid) {
|
||||
|
||||
if (wallet.cachedStatus.alternativeBalanceAvailable) {
|
||||
availableFundsInFiat = wallet.cachedStatus.spendableBalanceAlternative + ' ' + wallet.cachedStatus.alternativeIsoCode;
|
||||
} else {
|
||||
availableFundsInFiat = '';
|
||||
}
|
||||
walletSpendableAmount.crypto = wallet.cachedStatus.spendableBalanceStr;
|
||||
walletSpendableAmount.satoshis = wallet.cachedStatus.spendableAmount;
|
||||
|
||||
} else {
|
||||
|
||||
walletSpendableAmount.crypto = '';
|
||||
walletSpendableAmount.satoshis = null;
|
||||
}
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
vm.availableFunds = availableFundsInFiat || walletSpendableAmount.crypto;
|
||||
} else {
|
||||
vm.availableFunds = walletSpendableAmount.crypto;
|
||||
}
|
||||
|
||||
setMaximumButtonFromWallet(wallet);
|
||||
}
|
||||
|
||||
function updateMaximumButtonIfNeeded() {
|
||||
console.log('sendmax updateMaximumButtonIfNeeded()');
|
||||
if (vm.showSendMaxButton || vm.showSendLimitMaxButton) {
|
||||
transactionSendableAmount.fiat = '';
|
||||
vm.sendableFunds = transactionSendableAmount.crypto;
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
var coin = availableUnits[altUnitIndex].id;
|
||||
txFormatService.formatAlternativeStr(coin, transactionSendableAmount.satoshis, function formatCallback(formatted){
|
||||
if (formatted) {
|
||||
$scope.$apply(function onApply() {
|
||||
vm.sendableFunds = formatted;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -619,37 +716,59 @@ function amountController(configService, $filter, gettextCatalog, $ionicModal, $
|
|||
}
|
||||
}
|
||||
|
||||
function updateAvailableFundsFromWallet(wallet) {
|
||||
if (wallet.status && wallet.status.isValid) {
|
||||
availableFundsInCrypto = wallet.status.spendableBalanceStr;
|
||||
availableSatoshis = wallet.status.spendableAmount;
|
||||
if (wallet.status.alternativeBalanceAvailable) {
|
||||
availableFundsInFiat = wallet.status.spendableBalanceAlternative + ' ' + wallet.status.alternativeIsoCode;
|
||||
function setMaximumButtonFromWallet(wallet) {
|
||||
console.log('sendmax setMaximumButtonFromWallet()');
|
||||
var minSatoshis = vm.minAmount * unitToSatoshi;
|
||||
var maxSatoshis = vm.maxAmount * unitToSatoshi;
|
||||
|
||||
if (minSatoshis > walletSpendableAmount.satoshis) {
|
||||
console.log('sendmax Hiding max buttons as minimum is too high.');
|
||||
canSendMax = false;
|
||||
vm.showSendMaxButton = true;
|
||||
vm.showSendLimitMaxButton = false;
|
||||
transactionSendableAmount.satoshis = walletSpendableAmount.satoshis;
|
||||
|
||||
} else if (maxSatoshis) {
|
||||
if (walletSpendableAmount.satoshis > maxSatoshis) {
|
||||
console.log('sendmax Showing max limit button as available is greater than max limit.');
|
||||
canSendMax = false;
|
||||
vm.showSendMaxButton = false;
|
||||
vm.showSendLimitMaxButton = true;
|
||||
transactionSendableAmount.satoshis = maxSatoshis;
|
||||
} else {
|
||||
availableFundsInFiat = '';
|
||||
console.log('sendmax Showing sendmax as all available as less than max limit.');
|
||||
// Enabling send max here is a little dangerous, if they receive funds between pressing
|
||||
// this and the calculation in the Review screen.
|
||||
canSendMax = false;
|
||||
vm.showSendMaxButton = true;
|
||||
vm.showSendLimitMaxButton = false;
|
||||
transactionSendableAmount.satoshis = walletSpendableAmount.satoshis;
|
||||
}
|
||||
|
||||
} else if (wallet.cachedStatus && wallet.status.isValid) {
|
||||
} else {
|
||||
console.log('sendmax Showing sendmax as all available because no limits.');
|
||||
canSendMax = true;
|
||||
vm.showSendMaxButton = true;
|
||||
vm.showSendLimitMaxButton = false;
|
||||
transactionSendableAmount.satoshis = walletSpendableAmount.satoshis;
|
||||
}
|
||||
|
||||
if (wallet.cachedStatus.alternativeBalanceAvailable) {
|
||||
availableFundsInFiat = wallet.cachedStatus.spendableBalanceAlternative + ' ' + wallet.cachedStatus.alternativeIsoCode;
|
||||
} else {
|
||||
availableFundsInFiat = '';
|
||||
if (vm.showSendMaxButton || vm.showSendLimitMaxButton) {
|
||||
console.log('sendmax Setting max button text');
|
||||
transactionSendableAmount.crypto = txFormatService.formatAmountStr(wallet.coin, transactionSendableAmount.satoshis);
|
||||
vm.sendableFunds = transactionSendableAmount.crypto;
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
txFormatService.formatAlternativeStr(wallet.coin, transactionSendableAmount.satoshis, function onFormat(formatted){
|
||||
if (formatted) {
|
||||
$scope.$apply(function onApply() {
|
||||
vm.sendableFunds = formatted;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
availableFundsInCrypto = wallet.cachedStatus.spendableBalanceStr;
|
||||
availableSatoshis = wallet.cachedStatus.spendableAmount;
|
||||
|
||||
} else {
|
||||
|
||||
availableFundsInFiat = '';
|
||||
availableFundsInCrypto = '';
|
||||
availableSatoshis = null;
|
||||
}
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
vm.availableFunds = availableFundsInFiat || availableFundsInCrypto;
|
||||
} else {
|
||||
vm.availableFunds = availableFundsInCrypto;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -1,14 +1,20 @@
|
|||
describe('amountController', function(){
|
||||
var configCache,
|
||||
configService,
|
||||
configService,
|
||||
gettextCatalog,
|
||||
$controller,
|
||||
$ionicHistory,
|
||||
$rootScope,
|
||||
ongoingProcess,
|
||||
platformInfo,
|
||||
popupService,
|
||||
profileService,
|
||||
rateService,
|
||||
sendFlowService,
|
||||
shapeshiftService,
|
||||
txFormatService,
|
||||
$scope,
|
||||
$state,
|
||||
$stateParams;
|
||||
|
||||
|
||||
|
|
@ -20,7 +26,7 @@ describe('amountController', function(){
|
|||
configCache = {
|
||||
wallet: {
|
||||
settings: {
|
||||
|
||||
unitToSatoshi: 100000000
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -33,20 +39,42 @@ describe('amountController', function(){
|
|||
});
|
||||
configService.getSync.and.returnValue(configCache);
|
||||
|
||||
gettextCatalog = jasmine.createSpyObj(['getString']);
|
||||
gettextCatalog.getString.and.callFake(function(str){ return str; });
|
||||
$ionicHistory = jasmine.createSpyObj(['backView']);
|
||||
|
||||
ongoingProcess = jasmine.createSpyObj(['set']);
|
||||
|
||||
platformInfo = {
|
||||
isChromeApp: false,
|
||||
isAndroid: false,
|
||||
isIos: true
|
||||
};
|
||||
|
||||
popupService = jasmine.createSpyObj(['showAlert']);
|
||||
profileService = jasmine.createSpyObj(['getWallet', 'getWallets']);
|
||||
|
||||
rateService = jasmine.createSpyObj(['fromFiat', 'whenAvailable']);
|
||||
sendFlowService = jasmine.createSpyObj(['getStateClone']);
|
||||
shapeshiftService = jasmine.createSpyObj(['shiftIt']);
|
||||
rateService = jasmine.createSpyObj(['fromFiat', 'listAlternatives', 'updateRates', 'whenAvailable']);
|
||||
sendFlowService = jasmine.createSpyObj(['getStateClone', 'pushState']);
|
||||
shapeshiftService = jasmine.createSpyObj(['getMarketData']);
|
||||
txFormatService = jasmine.createSpyObj(['formatAlternativeStr', 'formatAmountStr']);
|
||||
|
||||
txFormatService.formatAlternativeStr.and.callFake(function(coin, satoshis, cb) {
|
||||
if (typeof satoshis !== "number") {
|
||||
throw "satoshis in formatAlternativeStr() is not a number."
|
||||
}
|
||||
var units = satoshis / 100000000;
|
||||
var formatted = (units * 10000).toFixed(2) + ' USD';
|
||||
cb(formatted);
|
||||
});
|
||||
|
||||
txFormatService.formatAmountStr.and.callFake(function(coin, satoshis) {
|
||||
if (typeof satoshis !== "number") {
|
||||
throw "satoshis in formatAmountStr() is not a number."
|
||||
}
|
||||
return (satoshis * 100000000).toFixed(8) + ' ' + (coin || 'bch').toUpperCase();
|
||||
});
|
||||
|
||||
$state = jasmine.createSpyObj(['transitionTo']);
|
||||
$stateParams = {};
|
||||
|
||||
inject(function(_$controller_, _$rootScope_){
|
||||
|
|
@ -67,7 +95,10 @@ describe('amountController', function(){
|
|||
$ionicHistory.backView.and.returnValue(backView);
|
||||
|
||||
var wallet = {
|
||||
|
||||
status: {
|
||||
isValid: true,
|
||||
spendableAmount: 123456
|
||||
}
|
||||
};
|
||||
profileService.getWallet.and.returnValue(wallet);
|
||||
profileService.getWallets.and.returnValue([{}]);
|
||||
|
|
@ -78,22 +109,22 @@ describe('amountController', function(){
|
|||
|
||||
var amountController = $controller('amountController', {
|
||||
configService: configService,
|
||||
gettextCatalog: {},
|
||||
gettextCatalog: gettextCatalog,
|
||||
$ionicHistory: $ionicHistory,
|
||||
$ionicModal: {},
|
||||
$ionicScrollDelegate: {},
|
||||
nodeWebkitService: {},
|
||||
ongoingProcess: {},
|
||||
ongoingProcess: ongoingProcess,
|
||||
platformInfo: platformInfo,
|
||||
profileService: profileService,
|
||||
popupService: {},
|
||||
popupService: popupService,
|
||||
rateService: rateService,
|
||||
$scope: $scope,
|
||||
sendFlowService: sendFlowService,
|
||||
shapeshiftService: shapeshiftService,
|
||||
$state: {},
|
||||
$stateParams: $stateParams,
|
||||
txFormatService: {},
|
||||
txFormatService: txFormatService,
|
||||
walletService: {}
|
||||
});
|
||||
|
||||
|
|
@ -110,4 +141,464 @@ describe('amountController', function(){
|
|||
//expect($scope.toAddress).toBe('qrup46avn8t466xxwlzs4qelht7cnwvesv2e29wf7s');
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe('Shapeshift', function() {
|
||||
var walletFrom;
|
||||
var walletTo;
|
||||
|
||||
beforeEach(function(){
|
||||
walletFrom = {};
|
||||
walletTo = {};
|
||||
|
||||
profileService.getWallet.and.callFake(function(walletId){
|
||||
if (walletId === '4cd7673e-7320-4dfa-86e5-d4edb51d460a') {
|
||||
return walletFrom;
|
||||
} else if (walletId === 'bf00af8f-0788-4b57-b30a-0390747407e9') {
|
||||
return walletTo;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
rateService.listAlternatives.and.returnValue([
|
||||
{name: "Australian Dollar", isoCode: "AUD"},
|
||||
{name: "United States Dollar", isoCode: "USD"}
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
it ('with available balance below limit, shows sendMax for triggering alert', function() {
|
||||
|
||||
walletFrom.coin = 'btc';
|
||||
walletFrom.status = {
|
||||
isValid: true,
|
||||
spendableAmount: 789
|
||||
};
|
||||
walletTo.coin = 'bch';
|
||||
|
||||
profileService.getWallets.and.returnValue([{}]);
|
||||
rateService.fromFiat.and.returnValue(12);
|
||||
|
||||
var $scope = $rootScope.$new();
|
||||
|
||||
var amountController = $controller('amountController', {
|
||||
configService: configService,
|
||||
gettextCatalog: gettextCatalog,
|
||||
$ionicHistory: $ionicHistory,
|
||||
$ionicModal: {},
|
||||
$ionicScrollDelegate: {},
|
||||
nodeWebkitService: {},
|
||||
ongoingProcess: ongoingProcess,
|
||||
platformInfo: platformInfo,
|
||||
profileService: profileService,
|
||||
popupService: popupService,
|
||||
rateService: rateService,
|
||||
$scope: $scope,
|
||||
sendFlowService: sendFlowService,
|
||||
shapeshiftService: shapeshiftService,
|
||||
$state: $state,
|
||||
$stateParams: $stateParams,
|
||||
txFormatService: txFormatService,
|
||||
walletService: {}
|
||||
});
|
||||
|
||||
rateService.whenAvailable.and.callFake(function(cb){
|
||||
cb();
|
||||
});
|
||||
|
||||
var sendFlowState = {
|
||||
amount: '',
|
||||
displayAddress: null,
|
||||
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
|
||||
sendMax: false,
|
||||
thirdParty: {
|
||||
id: 'shapeshift',
|
||||
data: {},
|
||||
},
|
||||
toAddress: '',
|
||||
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
|
||||
};
|
||||
|
||||
sendFlowService.getStateClone.and.returnValue(sendFlowState);
|
||||
|
||||
var reqCoinIn = '';
|
||||
var reqCoinOut = '';
|
||||
shapeshiftService.getMarketData.and.callFake(function(coinIn, coinOut, cb){
|
||||
reqCoinIn = coinIn;
|
||||
reqCoinOut = coinOut;
|
||||
cb({
|
||||
maxLimit: '0.6846239',
|
||||
minimum: '0.00013692'
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$emit('$ionicView.beforeEnter', {});
|
||||
|
||||
expect(rateService.updateRates.calls.any()).toEqual(true);
|
||||
|
||||
expect(reqCoinIn).toBe('btc');
|
||||
expect(reqCoinOut).toBe('bch');
|
||||
|
||||
expect(amountController.maxAmount).toBe(0.68462390);
|
||||
expect(amountController.minAmount).toBe(0.00013692);
|
||||
|
||||
expect(amountController.showSendMaxButton).toEqual(true);
|
||||
expect(amountController.showSendLimitMaxButton).toEqual(false);
|
||||
|
||||
expect(amountController.sendableFunds).toEqual('0.08 USD');
|
||||
|
||||
// Now hit the Send Max button
|
||||
amountController.sendMax();
|
||||
|
||||
expect(popupService.showAlert.calls.argsFor(0)[0]).toEqual('Insufficient funds');
|
||||
expect(popupService.showAlert.calls.argsFor(0)[1]).toEqual('Amount below minimum allowed');
|
||||
expect(sendFlowService.pushState.calls.any()).toEqual(false);
|
||||
expect($state.transitionTo.calls.any()).toEqual(false);
|
||||
});
|
||||
|
||||
it ('with available balance between limits, uses sendMax', function() {
|
||||
|
||||
walletFrom.coin = 'btc';
|
||||
walletFrom.status = {
|
||||
isValid: true,
|
||||
spendableAmount: 456789
|
||||
};
|
||||
walletTo.coin = 'bch';
|
||||
|
||||
profileService.getWallets.and.returnValue([{}]);
|
||||
rateService.fromFiat.and.returnValue(12);
|
||||
|
||||
var $scope = $rootScope.$new();
|
||||
|
||||
var amountController = $controller('amountController', {
|
||||
configService: configService,
|
||||
gettextCatalog: {},
|
||||
$ionicHistory: $ionicHistory,
|
||||
$ionicModal: {},
|
||||
$ionicScrollDelegate: {},
|
||||
nodeWebkitService: {},
|
||||
ongoingProcess: ongoingProcess,
|
||||
platformInfo: platformInfo,
|
||||
profileService: profileService,
|
||||
popupService: {},
|
||||
rateService: rateService,
|
||||
$scope: $scope,
|
||||
sendFlowService: sendFlowService,
|
||||
shapeshiftService: shapeshiftService,
|
||||
$state: $state,
|
||||
$stateParams: $stateParams,
|
||||
txFormatService: txFormatService,
|
||||
walletService: {}
|
||||
});
|
||||
|
||||
rateService.whenAvailable.and.callFake(function(cb){
|
||||
cb();
|
||||
});
|
||||
|
||||
var sendFlowState = {
|
||||
amount: '',
|
||||
displayAddress: null,
|
||||
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
|
||||
sendMax: false,
|
||||
thirdParty: {
|
||||
id: 'shapeshift',
|
||||
data: {},
|
||||
},
|
||||
toAddress: '',
|
||||
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
|
||||
};
|
||||
|
||||
sendFlowService.getStateClone.and.returnValue(sendFlowState);
|
||||
|
||||
var reqCoinIn = '';
|
||||
var reqCoinOut = '';
|
||||
shapeshiftService.getMarketData.and.callFake(function(coinIn, coinOut, cb){
|
||||
reqCoinIn = coinIn;
|
||||
reqCoinOut = coinOut;
|
||||
cb({
|
||||
maxLimit: '0.6846239',
|
||||
minimum: '0.00013692'
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$emit('$ionicView.beforeEnter', {});
|
||||
|
||||
expect(rateService.updateRates.calls.any()).toEqual(true);
|
||||
|
||||
expect(reqCoinIn).toBe('btc');
|
||||
expect(reqCoinOut).toBe('bch');
|
||||
|
||||
expect(amountController.maxAmount).toBe(0.68462390);
|
||||
expect(amountController.minAmount).toBe(0.00013692);
|
||||
|
||||
expect(amountController.showSendMaxButton).toEqual(true);
|
||||
expect(amountController.showSendLimitMaxButton).toEqual(false);
|
||||
|
||||
// Now hit the Send Max button
|
||||
var pushedState = null;
|
||||
sendFlowService.pushState.and.callFake(function (sendFlowState){
|
||||
pushedState = sendFlowState;
|
||||
});
|
||||
|
||||
amountController.sendMax();
|
||||
|
||||
expect(pushedState.amount).toBeUndefined();
|
||||
expect(pushedState.fromWalletId).toEqual('4cd7673e-7320-4dfa-86e5-d4edb51d460a');
|
||||
expect(pushedState.sendMax).toEqual(true);
|
||||
expect(pushedState.toWalletId).toEqual('bf00af8f-0788-4b57-b30a-0390747407e9');
|
||||
|
||||
expect(pushedState.thirdParty.id).toEqual('shapeshift');
|
||||
expect(pushedState.thirdParty.data.maxAmount).toEqual(0.6846239);
|
||||
expect(pushedState.thirdParty.data.minAmount).toEqual(0.00013692);
|
||||
|
||||
expect($state.transitionTo.calls.count()).toEqual(1);
|
||||
expect($state.transitionTo.calls.argsFor(0)[0]).toEqual('tabs.send.review');
|
||||
});
|
||||
|
||||
it ('with available balance higher than max, uses send limit max instead of sendMax', function() {
|
||||
|
||||
walletFrom.coin = 'btc';
|
||||
walletFrom.status = {
|
||||
isValid: true,
|
||||
spendableAmount: 123456789
|
||||
};
|
||||
walletTo.coin = 'bch';
|
||||
|
||||
profileService.getWallets.and.returnValue([{}]);
|
||||
rateService.fromFiat.and.returnValue(12); // satoshis or coins?
|
||||
|
||||
var $scope = $rootScope.$new();
|
||||
|
||||
var amountController = $controller('amountController', {
|
||||
configService: configService,
|
||||
gettextCatalog: {},
|
||||
$ionicHistory: $ionicHistory,
|
||||
$ionicModal: {},
|
||||
$ionicScrollDelegate: {},
|
||||
nodeWebkitService: {},
|
||||
ongoingProcess: ongoingProcess,
|
||||
platformInfo: platformInfo,
|
||||
profileService: profileService,
|
||||
popupService: {},
|
||||
rateService: rateService,
|
||||
$scope: $scope,
|
||||
sendFlowService: sendFlowService,
|
||||
shapeshiftService: shapeshiftService,
|
||||
$state: $state,
|
||||
$stateParams: $stateParams,
|
||||
txFormatService: txFormatService,
|
||||
walletService: {}
|
||||
});
|
||||
|
||||
rateService.whenAvailable.and.callFake(function(cb){
|
||||
cb();
|
||||
});
|
||||
|
||||
var sendFlowState = {
|
||||
amount: '',
|
||||
displayAddress: null,
|
||||
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
|
||||
sendMax: false,
|
||||
thirdParty: {
|
||||
id: 'shapeshift',
|
||||
data: {},
|
||||
},
|
||||
toAddress: '',
|
||||
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
|
||||
};
|
||||
|
||||
sendFlowService.getStateClone.and.returnValue(sendFlowState);
|
||||
|
||||
var reqCoinIn = '';
|
||||
var reqCoinOut = '';
|
||||
shapeshiftService.getMarketData.and.callFake(function(coinIn, coinOut, cb){
|
||||
reqCoinIn = coinIn;
|
||||
reqCoinOut = coinOut;
|
||||
cb({
|
||||
maxLimit: '0.6846239',
|
||||
minimum: '0.00013692'
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$emit('$ionicView.beforeEnter', {});
|
||||
|
||||
expect(rateService.updateRates.calls.any()).toEqual(true);
|
||||
|
||||
expect(reqCoinIn).toBe('btc');
|
||||
expect(reqCoinOut).toBe('bch');
|
||||
|
||||
expect(amountController.maxAmount).toBe(0.6846239);
|
||||
expect(amountController.minAmount).toBe(0.00013692);
|
||||
|
||||
expect(amountController.showSendMaxButton).toEqual(false);
|
||||
expect(amountController.showSendLimitMaxButton).toEqual(true);
|
||||
|
||||
// Now hit the Send Max button
|
||||
var pushedState = null;
|
||||
sendFlowService.pushState.and.callFake(function (sendFlowState){
|
||||
pushedState = sendFlowState;
|
||||
});
|
||||
|
||||
amountController.sendMax();
|
||||
|
||||
expect(pushedState.amount).toEqual(68462390);
|
||||
expect(pushedState.fromWalletId).toEqual('4cd7673e-7320-4dfa-86e5-d4edb51d460a');
|
||||
expect(pushedState.sendMax).toEqual(false);
|
||||
expect(pushedState.toWalletId).toEqual('bf00af8f-0788-4b57-b30a-0390747407e9');
|
||||
|
||||
expect(pushedState.thirdParty.id).toEqual('shapeshift');
|
||||
expect(pushedState.thirdParty.data.maxAmount).toEqual(0.6846239);
|
||||
expect(pushedState.thirdParty.data.minAmount).toEqual(0.00013692);
|
||||
|
||||
expect($state.transitionTo.calls.count()).toEqual(1);
|
||||
expect($state.transitionTo.calls.argsFor(0)[0]).toEqual('tabs.send.review');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Wallet transfer', function() {
|
||||
var walletFrom;
|
||||
var walletTo;
|
||||
|
||||
beforeEach(function(){
|
||||
walletFrom = {};
|
||||
walletTo = {};
|
||||
|
||||
profileService.getWallet.and.callFake(function(walletId){
|
||||
if (walletId === '4cd7673e-7320-4dfa-86e5-d4edb51d460a') {
|
||||
return walletFrom;
|
||||
} else if (walletId === 'bf00af8f-0788-4b57-b30a-0390747407e9') {
|
||||
return walletTo;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
rateService.listAlternatives.and.returnValue([
|
||||
{name: "Australian Dollar", isoCode: "AUD"},
|
||||
{name: "United States Dollar", isoCode: "USD"}
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
it('wallet transfer send max.', function() {
|
||||
|
||||
walletFrom.coin = 'btc';
|
||||
walletFrom.status = {
|
||||
isValid: true,
|
||||
spendableAmount: 123456789
|
||||
};
|
||||
|
||||
profileService.getWallets.and.returnValue([{}]);
|
||||
|
||||
var $scope = $rootScope.$new();
|
||||
|
||||
var amountController = $controller('amountController', {
|
||||
configService: configService,
|
||||
gettextCatalog: gettextCatalog,
|
||||
$ionicHistory: $ionicHistory,
|
||||
$ionicModal: {},
|
||||
$ionicScrollDelegate: {},
|
||||
nodeWebkitService: {},
|
||||
ongoingProcess: ongoingProcess,
|
||||
platformInfo: platformInfo,
|
||||
profileService: profileService,
|
||||
popupService: popupService,
|
||||
rateService: rateService,
|
||||
$scope: $scope,
|
||||
sendFlowService: sendFlowService,
|
||||
shapeshiftService: shapeshiftService,
|
||||
$state: $state,
|
||||
$stateParams: $stateParams,
|
||||
txFormatService: txFormatService,
|
||||
walletService: {}
|
||||
});
|
||||
|
||||
var sendFlowState = {
|
||||
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
|
||||
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
|
||||
};
|
||||
|
||||
sendFlowService.getStateClone.and.returnValue(sendFlowState);
|
||||
|
||||
$scope.$emit('$ionicView.beforeEnter', {});
|
||||
|
||||
expect(amountController.showSendMaxButton).toEqual(true);
|
||||
expect(amountController.showSendLimitMaxButton).toEqual(false);
|
||||
|
||||
expect(amountController.sendableFunds).toEqual('12345.68 USD');
|
||||
|
||||
// Now hit the Send Max button
|
||||
var pushedState = null;
|
||||
sendFlowService.pushState.and.callFake(function (sendFlowState){
|
||||
pushedState = sendFlowState;
|
||||
});
|
||||
|
||||
amountController.sendMax();
|
||||
|
||||
expect(pushedState.amount).toBeUndefined();
|
||||
expect(pushedState.fromWalletId).toEqual('4cd7673e-7320-4dfa-86e5-d4edb51d460a');
|
||||
expect(pushedState.sendMax).toEqual(true);
|
||||
expect(pushedState.toWalletId).toEqual('bf00af8f-0788-4b57-b30a-0390747407e9');
|
||||
|
||||
expect($state.transitionTo.calls.count()).toEqual(1);
|
||||
expect($state.transitionTo.calls.argsFor(0)[0]).toEqual('tabs.send.review');
|
||||
});
|
||||
|
||||
|
||||
// This situation was seen in real life
|
||||
it('wallet transfer with valid cached status only.', function() {
|
||||
|
||||
walletFrom.coin = 'btc';
|
||||
walletFrom.status = {
|
||||
isValid: false,
|
||||
};
|
||||
walletFrom.cachedStatus = {
|
||||
isValid: true,
|
||||
spendableAmount: 5678
|
||||
};
|
||||
|
||||
profileService.getWallets.and.returnValue([{}]);
|
||||
|
||||
var $scope = $rootScope.$new();
|
||||
|
||||
var amountController = $controller('amountController', {
|
||||
configService: configService,
|
||||
gettextCatalog: gettextCatalog,
|
||||
$ionicHistory: $ionicHistory,
|
||||
$ionicModal: {},
|
||||
$ionicScrollDelegate: {},
|
||||
nodeWebkitService: {},
|
||||
ongoingProcess: ongoingProcess,
|
||||
platformInfo: platformInfo,
|
||||
profileService: profileService,
|
||||
popupService: popupService,
|
||||
rateService: rateService,
|
||||
$scope: $scope,
|
||||
sendFlowService: sendFlowService,
|
||||
shapeshiftService: shapeshiftService,
|
||||
$state: $state,
|
||||
$stateParams: $stateParams,
|
||||
txFormatService: txFormatService,
|
||||
walletService: {}
|
||||
});
|
||||
|
||||
var sendFlowState = {
|
||||
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
|
||||
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
|
||||
};
|
||||
|
||||
sendFlowService.getStateClone.and.returnValue(sendFlowState);
|
||||
|
||||
$scope.$emit('$ionicView.beforeEnter', {});
|
||||
|
||||
expect(amountController.showSendMaxButton).toEqual(true);
|
||||
expect(amountController.showSendLimitMaxButton).toEqual(false);
|
||||
|
||||
expect(amountController.sendableFunds).toEqual('0.57 USD');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.controllers').controller('tourController',
|
||||
function($scope, $state, $log, $timeout, $filter, ongoingProcess, profileService, rateService, popupService, gettextCatalog, startupService, storageService, walletService, $q) {
|
||||
function ($scope, $state, $log, $timeout, $filter, ongoingProcess, configService, profileService, rateService, popupService, gettextCatalog, lodash, startupService, storageService, uxLanguage, walletService, $q) {
|
||||
|
||||
$scope.data = {
|
||||
index: 0
|
||||
|
|
@ -46,62 +46,90 @@ angular.module('copayApp.controllers').controller('tourController',
|
|||
creatingWallet = true;
|
||||
ongoingProcess.set('creatingWallet', true);
|
||||
$timeout(function() {
|
||||
profileService.createDefaultWallet(function(err, walletClients) {
|
||||
if (err) {
|
||||
$log.warn(err);
|
||||
uxLanguage.init(function(lang) {
|
||||
var rateCode = uxLanguage.getRateCode(lang);
|
||||
console.log("When Available: rateService");
|
||||
rateService.whenAvailable(function() {
|
||||
var alternatives = rateService.listAlternatives(true);
|
||||
|
||||
return $timeout(function() {
|
||||
$log.warn('Retrying to create default wallet.....:' + ++retryCount);
|
||||
if (retryCount > 3) {
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
popupService.showAlert(
|
||||
gettextCatalog.getString('Cannot Create Wallet'), err,
|
||||
function() {
|
||||
retryCount = 0;
|
||||
return $scope.createDefaultWallet();
|
||||
}, gettextCatalog.getString('Retry'));
|
||||
} else {
|
||||
return $scope.createDefaultWallet();
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
var bchWallet = walletClients[0];
|
||||
var btcWallet = walletClients[1];
|
||||
var bchWalletId = bchWallet.credentials.walletId;
|
||||
var btcWalletId = btcWallet.credentials.walletId;
|
||||
|
||||
function createAddressPromise(wallet) {
|
||||
return $q(function(resolve, reject) {
|
||||
walletService.getAddress(wallet, true, function(e, addr) {
|
||||
if (e) reject(e);
|
||||
resolve(addr);
|
||||
var newAltCurrency = lodash.find(alternatives, {
|
||||
'isoCode': rateCode
|
||||
});
|
||||
|
||||
configService.whenAvailable(function(config) {
|
||||
var opts = {
|
||||
wallet: {
|
||||
settings: {
|
||||
alternativeName: newAltCurrency.name,
|
||||
alternativeIsoCode: newAltCurrency.isoCode,
|
||||
}
|
||||
}
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.warn(err);
|
||||
|
||||
profileService.createDefaultWallet(function(err, walletClients) {
|
||||
if (err) {
|
||||
$log.warn(err);
|
||||
|
||||
return $timeout(function() {
|
||||
$log.warn('Retrying to create default wallet.....:' + ++retryCount);
|
||||
if (retryCount > 3) {
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
popupService.showAlert(
|
||||
gettextCatalog.getString('Cannot Create Wallet'), err,
|
||||
function() {
|
||||
retryCount = 0;
|
||||
return $scope.createDefaultWallet();
|
||||
}, gettextCatalog.getString('Retry'));
|
||||
} else {
|
||||
return $scope.createDefaultWallet();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
;
|
||||
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
var bchWallet = walletClients[0];
|
||||
var btcWallet = walletClients[1];
|
||||
var bchWalletId = bchWallet.credentials.walletId;
|
||||
var btcWalletId = btcWallet.credentials.walletId;
|
||||
|
||||
function createAddressPromise(wallet) {
|
||||
return $q(function (resolve, reject) {
|
||||
walletService.getAddress(wallet, true, function (e, addr) {
|
||||
if (e) reject(e);
|
||||
resolve(addr);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function goToCollectEmail() {
|
||||
$state.go('onboarding.collectEmail', {
|
||||
bchWalletId: bchWalletId,
|
||||
btcWalletId: btcWalletId
|
||||
});
|
||||
}
|
||||
|
||||
var bchAddressPromise = createAddressPromise(bchWallet);
|
||||
var btcAddressPromise = createAddressPromise(btcWallet);
|
||||
ongoingProcess.set('generatingNewAddress', true);
|
||||
|
||||
$q.all([bchAddressPromise, btcAddressPromise]).then(function (addresses) {
|
||||
ongoingProcess.set('generatingNewAddress', false);
|
||||
$state.go('tabs.home');
|
||||
}, function (e) {
|
||||
ongoingProcess.set('generatingNewAddress', false);
|
||||
$log.warn(e);
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), e);
|
||||
$state.go('tabs.home');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
$log.debug('Setting default currency : ' + newAltCurrency);
|
||||
});
|
||||
}
|
||||
|
||||
function goToCollectEmail() {
|
||||
$state.go('onboarding.collectEmail', {
|
||||
bchWalletId: bchWalletId,
|
||||
btcWalletId: btcWalletId
|
||||
});
|
||||
}
|
||||
|
||||
var bchAddressPromise = createAddressPromise(bchWallet);
|
||||
var btcAddressPromise = createAddressPromise(btcWallet);
|
||||
ongoingProcess.set('generatingNewAddress', true);
|
||||
|
||||
$q.all([bchAddressPromise, btcAddressPromise]).then(function(addresses) {
|
||||
ongoingProcess.set('generatingNewAddress', false);
|
||||
$state.go('tabs.home');
|
||||
}, function(e) {
|
||||
ongoingProcess.set('generatingNewAddress', false);
|
||||
$log.warn(e);
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), e);
|
||||
$state.go('tabs.home');
|
||||
});
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
});
|
||||
})
|
||||
}, 300);
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,21 +43,20 @@ angular.module('copayApp.controllers').controller('tabHomeController',
|
|||
});
|
||||
}
|
||||
|
||||
if ($scope.isNW) {
|
||||
latestReleaseService.checkLatestRelease(function(err, newRelease) {
|
||||
if (err) {
|
||||
$log.warn(err);
|
||||
return;
|
||||
}
|
||||
if (newRelease) {
|
||||
$scope.newRelease = true;
|
||||
$scope.updateText = gettextCatalog.getString('There is a new version of {{appName}} available', {
|
||||
appName: $scope.name
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
latestReleaseService.checkLatestRelease(function(err, newReleaseData) {
|
||||
if (err) {
|
||||
$log.warn(err);
|
||||
return;
|
||||
}
|
||||
if (newReleaseData) {
|
||||
$scope.newRelease = true;
|
||||
$scope.newReleaseText = gettextCatalog.getString('There is a new version of {{appName}} available', {
|
||||
appName: $scope.name
|
||||
});
|
||||
$scope.newReleaseNotes = newReleaseData.releaseNotes;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onEnter(event, data) {
|
||||
$ionicNavBarDelegate.showBar(true);
|
||||
|
|
@ -109,13 +108,13 @@ angular.module('copayApp.controllers').controller('tabHomeController',
|
|||
$scope.$apply();
|
||||
}, 10);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function onLeave (event, data) {
|
||||
lodash.each(listeners, function(x) {
|
||||
x();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
$scope.createdWithinPastDay = function(time) {
|
||||
return timeService.withinPastDay(time);
|
||||
|
|
@ -125,14 +124,8 @@ angular.module('copayApp.controllers').controller('tabHomeController',
|
|||
sendFlowService.start();
|
||||
}
|
||||
|
||||
$scope.openExternalLink = function() {
|
||||
var url = 'https://github.com/Bitcoin-com/Wallet/releases/latest';
|
||||
var optIn = true;
|
||||
var title = gettextCatalog.getString('Update Available');
|
||||
var message = gettextCatalog.getString('An update to this app is available. For your security, please update to the latest version.');
|
||||
var okText = gettextCatalog.getString('View Update');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
$scope.showUpdatePopup = function() {
|
||||
latestReleaseService.showUpdatePopup();
|
||||
};
|
||||
|
||||
$scope.openBannerUrl = function() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('tabReceiveController', function($rootScope, $scope, $timeout, $log, $ionicModal, $state, $ionicHistory, $ionicPopover, storageService, platformInfo, walletService, profileService, configService, lodash, gettextCatalog, popupService, bwcError, bitcoinCashJsService, $ionicNavBarDelegate, sendFlowService, txFormatService, soundService, clipboardService) {
|
||||
|
||||
var CLOSE_NORMAL = 1000;
|
||||
var listeners = [];
|
||||
$scope.bchAddressType = { type: 'cashaddr' };
|
||||
var bchAddresses = {};
|
||||
|
|
@ -10,12 +11,11 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
$scope.isCordova = platformInfo.isCordova;
|
||||
$scope.isNW = platformInfo.isNW;
|
||||
|
||||
var currentAddressSocket = {};
|
||||
var paymentSubscriptionObj = { op:"addr_sub" }
|
||||
|
||||
var config;
|
||||
var currentAddressSocket = null;
|
||||
var paymentSubscriptionObj = { op:'addr_sub' };
|
||||
|
||||
$scope.displayBalanceAsFiat = true;
|
||||
$scope.$on('$ionicView.beforeLeave', onBeforeLeave);
|
||||
|
||||
$scope.requestSpecificAmount = function() {
|
||||
sendFlowService.start({
|
||||
|
|
@ -24,6 +24,50 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
function connectSocket() {
|
||||
// Close existing socket if not connected with current address
|
||||
if (currentAddressSocket) {
|
||||
currentAddressSocket.close([CLOSE_NORMAL]);
|
||||
}
|
||||
|
||||
if ($scope.wallet.coin === 'bch') {
|
||||
// listen to bch address
|
||||
currentAddressSocket = new WebSocket('wss://ws.blockchain.info/bch/inv');
|
||||
paymentSubscriptionObj.addr = $scope.addrBchLegacy;
|
||||
} else {
|
||||
// listen to btc address
|
||||
currentAddressSocket = new WebSocket('wss://ws.blockchain.info/inv');
|
||||
paymentSubscriptionObj.addr = $scope.addr;
|
||||
}
|
||||
|
||||
// create subscription to address
|
||||
var msg = JSON.stringify(paymentSubscriptionObj);
|
||||
currentAddressSocket.onopen = function (event) {
|
||||
currentAddressSocket.send(msg);
|
||||
};
|
||||
|
||||
// listen for response
|
||||
currentAddressSocket.onmessage = function (event) {
|
||||
//console.log("message received:" + event.data);
|
||||
receivedPayment(event.data);
|
||||
};
|
||||
|
||||
currentAddressSocket.onclose = function(event) {
|
||||
if (event.code !== CLOSE_NORMAL) {
|
||||
$log.debug('Socket was closed abnormally. Reconnect will be attempted in 1 second.');
|
||||
$timeout(function() {
|
||||
connectSocket();
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
currentAddressSocket.onerror = function(err) {
|
||||
console.error('Socket encountered error: ', err, 'Closing socket');
|
||||
currentAddressSocket.close();
|
||||
};
|
||||
}
|
||||
|
||||
$scope.setAddress = function(newAddr, copyAddress) {
|
||||
$scope.addr = null;
|
||||
if (!$scope.wallet || $scope.generatingAddress || !$scope.wallet.isComplete()) return;
|
||||
|
|
@ -36,49 +80,24 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
popupService.showAlert(err);
|
||||
}
|
||||
|
||||
//close existing socket
|
||||
if (currentAddressSocket.close === 'function') {
|
||||
currentAddressSocket.close();
|
||||
}
|
||||
|
||||
if ($scope.wallet.coin == 'bch') {
|
||||
bchAddresses = bitcoinCashJsService.translateAddresses(addr);
|
||||
$scope.addr = bchAddresses[$scope.bchAddressType.type];
|
||||
$scope.addrBchLegacy = bchAddresses['legacy'];
|
||||
|
||||
// listen to bch address
|
||||
currentAddressSocket = new WebSocket("wss://ws.blockchain.info/bch/inv");
|
||||
paymentSubscriptionObj.addr = bchAddresses['legacy'];
|
||||
|
||||
if ($scope.wallet.coin === 'bch') {
|
||||
bchAddresses = bitcoinCashJsService.translateAddresses(addr);
|
||||
$scope.addr = bchAddresses[$scope.bchAddressType.type];
|
||||
$scope.addrBchLegacy = bchAddresses['legacy'];
|
||||
} else {
|
||||
$scope.addr = addr;
|
||||
|
||||
// listen to btc address
|
||||
currentAddressSocket = new WebSocket("wss://ws.blockchain.info/inv");
|
||||
paymentSubscriptionObj.addr = $scope.addr
|
||||
$scope.addr = addr;
|
||||
}
|
||||
|
||||
connectSocket();
|
||||
|
||||
if (copyAddress === true) {
|
||||
try {
|
||||
clipboardService.copyToClipboard($scope.wallet.coin == 'bch' && $scope.bchAddressType.type == 'cashaddr' ? 'bitcoincash:' + $scope.addr : $scope.addr);
|
||||
} catch (error) {
|
||||
$log.debug("Error copying to clipboard:");
|
||||
$log.debug('Error copying to clipboard:');
|
||||
$log.debug(error);
|
||||
}
|
||||
}
|
||||
// create subscription
|
||||
var msg = JSON.stringify(paymentSubscriptionObj);
|
||||
currentAddressSocket.onopen = function (event) {
|
||||
//console.log("message sent: " + msg);
|
||||
currentAddressSocket.send(msg);
|
||||
}
|
||||
|
||||
|
||||
// listen for response
|
||||
currentAddressSocket.onmessage = function (event) {
|
||||
//console.log("message received:" + event.data);
|
||||
receivedPayment(event.data);
|
||||
}
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
|
|
@ -164,7 +183,6 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
// Notify new tx
|
||||
$scope.$emit('bwsEvent', $scope.wallet.id);
|
||||
|
||||
|
||||
$scope.$apply(function () {
|
||||
$scope.showingPaymentReceived = true;
|
||||
});
|
||||
|
|
@ -233,6 +251,10 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
}
|
||||
};
|
||||
|
||||
function onBeforeLeave() {
|
||||
currentAddressSocket.close([CLOSE_NORMAL]);
|
||||
}
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.wallets = profileService.getWallets();
|
||||
$scope.singleWallet = $scope.wallets.length == 1;
|
||||
|
|
@ -258,7 +280,6 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
|
||||
configService.whenAvailable(function(_config) {
|
||||
$scope.displayBalanceAsFiat = _config.wallet.settings.priceDisplay === 'fiat';
|
||||
config = _config;
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,52 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, sendFlowService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService, feeService, appConfigService, rateService) {
|
||||
|
||||
var HISTORY_SHOW_LIMIT = 10;
|
||||
var currentTxHistoryPage = 0;
|
||||
angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, sendFlowService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService, feeService, appConfigService, rateService, walletHistoryService) {
|
||||
// Desktop can display 13 rows of transactions, bump it up to a nice round 15.
|
||||
var DISPLAY_PAGE_SIZE = 15;
|
||||
var currentTxHistoryDisplayPage = 0;
|
||||
var completeTxHistory = []
|
||||
var listeners = [];
|
||||
$scope.txps = [];
|
||||
$scope.completeTxHistory = [];
|
||||
$scope.openTxpModal = txpModalService.open;
|
||||
|
||||
// For gradual migration for doing it properly
|
||||
$scope.vm = {
|
||||
allowInfiniteScroll: false,
|
||||
gettingCachedHistory: true,
|
||||
gettingInitialHistory: true,
|
||||
updatingTxHistory: false,
|
||||
fetchedAllTxHistory: false,
|
||||
//updateTxHistoryError: false
|
||||
updateTxHistoryFailed: false
|
||||
};
|
||||
|
||||
// Need flag for when to allow infinite scroll at bottom
|
||||
// - ie not when loading initial data and there is no more cached data
|
||||
|
||||
$scope.amountIsCollapsible = false;
|
||||
$scope.color = '#888888';
|
||||
|
||||
$scope.filteredTxHistory = [];
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
$scope.isAndroid = platformInfo.isAndroid;
|
||||
$scope.isIOS = platformInfo.isIOS;
|
||||
$scope.isSearching = false;
|
||||
$scope.openTxpModal = txpModalService.open;
|
||||
$scope.requiresMultipleSignatures = false;
|
||||
$scope.showBalanceButton = false;
|
||||
$scope.status = null;
|
||||
// Displaying 50 transactions when entering the screen takes a while, so only display a subset
|
||||
// of everything we have, not the complete history.
|
||||
$scope.txHistory = []; // This is what is displayed
|
||||
$scope.txHistorySearchResults = [];
|
||||
$scope.txps = [];
|
||||
$scope.updatingStatus = false;
|
||||
$scope.updateStatusError = null;
|
||||
$scope.updatingTxHistoryProgress = 0;
|
||||
$scope.wallet = null;
|
||||
$scope.walletId = '';
|
||||
$scope.walletNotRegistered = false;
|
||||
|
||||
|
||||
|
||||
|
||||
var channel = "ga";
|
||||
if (platformInfo.isCordova) {
|
||||
|
|
@ -19,8 +55,6 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
var log = new window.BitAnalytics.LogEvent("wallet_details_open", [], [channel]);
|
||||
window.BitAnalytics.LogEventHandlers.postEvent(log);
|
||||
|
||||
$scope.amountIsCollapsible = !$scope.isAndroid;
|
||||
|
||||
$scope.openExternalLink = function(url, target) {
|
||||
externalLinkService.open(url, target);
|
||||
};
|
||||
|
|
@ -52,6 +86,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
$scope.updatingStatus = true;
|
||||
$scope.updateStatusError = null;
|
||||
$scope.walletNotRegistered = false;
|
||||
$scope.vm.fetchedAllTxHistory = false;
|
||||
|
||||
walletService.getStatus($scope.wallet, {
|
||||
force: !!force,
|
||||
|
|
@ -135,68 +170,97 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
if (err) return;
|
||||
$timeout(function() {
|
||||
walletService.startScan($scope.wallet, function() {
|
||||
$scope.updateAll();
|
||||
$scope.updateAll(true, true);
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var updateTxHistory = function(cb) {
|
||||
if (!cb) cb = function() {};
|
||||
$scope.updateTxHistoryError = false;
|
||||
$scope.updatingTxHistoryProgress = 0;
|
||||
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
|
||||
walletService.getTxHistory($scope.wallet, {
|
||||
feeLevels: levels
|
||||
}, function(err, txHistory) {
|
||||
$scope.updatingTxHistory = false;
|
||||
if (err) {
|
||||
$scope.txHistory = null;
|
||||
$scope.updateTxHistoryError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
applyCurrencyAliases(txHistory);
|
||||
|
||||
var config = configService.getSync();
|
||||
var fiatCode = config.wallet.settings.alternativeIsoCode;
|
||||
lodash.each(txHistory, function(t) {
|
||||
var r = rateService.toFiat(t.amount, fiatCode, $scope.wallet.coin);
|
||||
t.alternativeAmountStr = r.toFixed(2) + ' ' + fiatCode;
|
||||
});
|
||||
|
||||
$scope.completeTxHistory = txHistory;
|
||||
|
||||
$scope.showHistory();
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function applyCurrencyAliases(txHistory) {
|
||||
var defaults = configService.getDefaults();
|
||||
var configCache = configService.getSync();
|
||||
|
||||
lodash.each(txHistory, function(t) {
|
||||
t.amountUnitStr = $scope.wallet.coin == 'btc'
|
||||
lodash.each(txHistory, function onTx(tx) {
|
||||
tx.amountUnitStr = $scope.wallet.coin == 'btc'
|
||||
? (configCache.bitcoinAlias || defaults.bitcoinAlias)
|
||||
: (configCache.bitcoinCashAlias || defaults.bitcoinCashAlias);
|
||||
|
||||
t.amountUnitStr = t.amountUnitStr.toUpperCase();
|
||||
tx.amountUnitStr = tx.amountUnitStr.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.showHistory = function() {
|
||||
if ($scope.completeTxHistory) {
|
||||
$scope.txHistory = $scope.completeTxHistory.slice(0, (currentTxHistoryPage + 1) * HISTORY_SHOW_LIMIT);
|
||||
$scope.txHistoryShowMore = $scope.completeTxHistory.length > $scope.txHistory.length;
|
||||
function formatTxHistoryForDisplay(txHistory) {
|
||||
applyCurrencyAliases(txHistory);
|
||||
|
||||
var config = configService.getSync();
|
||||
var fiatCode = config.wallet.settings.alternativeIsoCode;
|
||||
lodash.each(txHistory, function(t) {
|
||||
var r = rateService.toFiat(t.amount, fiatCode, $scope.wallet.coin);
|
||||
t.alternativeAmountStr = r.toFixed(2) + ' ' + fiatCode;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function updateTxHistoryFromCachedData() {
|
||||
$scope.vm.gettingCachedHistory = true;
|
||||
walletHistoryService.getCachedTxHistory($scope.wallet.id, function onGetCachedTxHistory(err, txHistory){
|
||||
$scope.vm.gettingCachedHistory = false;
|
||||
if (err) {
|
||||
// Don't display an error because we are also requesting the history.
|
||||
$log.error('Error getting cached tx history.', err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!txHistory) {
|
||||
$log.debug('No cached tx history.');
|
||||
return;
|
||||
}
|
||||
|
||||
formatTxHistoryForDisplay(txHistory);
|
||||
|
||||
completeTxHistory = txHistory;
|
||||
showHistory(false);
|
||||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
|
||||
function fetchAndShowTxHistory(getLatest, flushCacheOnNew) {
|
||||
$scope.vm.updatingTxHistory = true;
|
||||
|
||||
walletHistoryService.updateLocalTxHistoryByPage($scope.wallet, getLatest, flushCacheOnNew, function onUpdateLocalTxHistoryByPage(err, txHistory, fetchedAllTransactions) {
|
||||
$scope.vm.gettingInitialHistory = false;
|
||||
$scope.vm.updatingTxHistory = false;
|
||||
$scope.$broadcast('scroll.infiniteScrollComplete');
|
||||
|
||||
if (err) {
|
||||
console.error('pagination Failed to get history.', err);
|
||||
$scope.vm.updateTxHistoryFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fetchedAllTransactions) {
|
||||
$scope.vm.fetchedAllTxHistory = true;
|
||||
}
|
||||
|
||||
formatTxHistoryForDisplay(txHistory);
|
||||
|
||||
completeTxHistory = txHistory;
|
||||
showHistory(true);
|
||||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function showHistory(showAll) {
|
||||
if (completeTxHistory) {
|
||||
$scope.txHistory = showAll ? completeTxHistory : completeTxHistory.slice(0, (currentTxHistoryDisplayPage + 1) * DISPLAY_PAGE_SIZE);
|
||||
$scope.vm.allowInfiniteScroll = !$scope.vm.fetchedAllTxHistory && !(completeTxHistory.length === $scope.txHistory.length && $scope.vm.gettingInitialHistory);
|
||||
} else {
|
||||
$scope.vm.allowInfiniteScroll = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
$scope.getDate = function(txCreated) {
|
||||
var date = new Date(txCreated * 1000);
|
||||
|
|
@ -235,24 +299,35 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
return !tx.confirmations || tx.confirmations === 0;
|
||||
};
|
||||
|
||||
// on-infinite="showMore()"
|
||||
$scope.showMore = function() {
|
||||
$timeout(function() {
|
||||
currentTxHistoryPage++;
|
||||
$scope.showHistory();
|
||||
// Check if we have more than we are displaying
|
||||
if (completeTxHistory.length > $scope.txHistory.length) {
|
||||
currentTxHistoryDisplayPage++;
|
||||
showHistory(false);
|
||||
$scope.$broadcast('scroll.infiniteScrollComplete');
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.vm.updatingTxHistory) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetchAndShowTxHistory(false, false);
|
||||
};
|
||||
|
||||
// on-refresh="onRefresh()"
|
||||
$scope.onRefresh = function() {
|
||||
$timeout(function() {
|
||||
$scope.$broadcast('scroll.refreshComplete');
|
||||
}, 300);
|
||||
$scope.updateAll(true);
|
||||
$scope.updateAll(true, false);
|
||||
};
|
||||
|
||||
$scope.updateAll = function(force, cb) {
|
||||
updateStatus(force);
|
||||
updateTxHistory(cb);
|
||||
$scope.updateAll = function(forceStatusUpdate, flushTxCacheOnNew) {
|
||||
updateStatus(forceStatusUpdate);
|
||||
//updateTxHistory(cb);
|
||||
fetchAndShowTxHistory(true, flushTxCacheOnNew);
|
||||
};
|
||||
|
||||
$scope.hideToggle = function() {
|
||||
|
|
@ -262,97 +337,32 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
};
|
||||
|
||||
var prevPos;
|
||||
|
||||
$scope.txHistoryPaddingBottom = 0;
|
||||
function getScrollPosition() {
|
||||
var scrollPosition = $ionicScrollDelegate.getScrollPosition();
|
||||
|
||||
$timeout(function() {
|
||||
getScrollPosition();
|
||||
}, 200);
|
||||
|
||||
if (!scrollPosition) {
|
||||
$window.requestAnimationFrame(function() {
|
||||
getScrollPosition();
|
||||
});
|
||||
return;
|
||||
}
|
||||
var pos = scrollPosition.top;
|
||||
if (pos > 0) {
|
||||
$scope.txHistoryPaddingBottom = "200px";
|
||||
}
|
||||
if (pos === prevPos) {
|
||||
$window.requestAnimationFrame(function() {
|
||||
getScrollPosition();
|
||||
});
|
||||
return;
|
||||
}
|
||||
prevPos = pos;
|
||||
refreshAmountSection(pos);
|
||||
};
|
||||
|
||||
function refreshAmountSection(scrollPos) {
|
||||
var AMOUNT_HEIGHT_BASE = 210;
|
||||
$scope.showBalanceButton = false;
|
||||
if ($scope.status) {
|
||||
$scope.showBalanceButton = ($scope.status.totalBalanceSat != $scope.status.spendableAmount);
|
||||
if ($scope.showBalanceButton) {
|
||||
AMOUNT_HEIGHT_BASE = 270;
|
||||
}
|
||||
}
|
||||
if (!$scope.amountIsCollapsible) {
|
||||
var t = ($scope.showBalanceButton ? 15 : 45);
|
||||
$scope.amountScale = 'translateY(' + t + 'px)';
|
||||
return;
|
||||
}
|
||||
|
||||
scrollPos = scrollPos || 0;
|
||||
var amountHeight = AMOUNT_HEIGHT_BASE - scrollPos;
|
||||
if (amountHeight < 80) {
|
||||
amountHeight = 80;
|
||||
}
|
||||
var contentMargin = amountHeight;
|
||||
if (contentMargin > AMOUNT_HEIGHT_BASE) {
|
||||
contentMargin = AMOUNT_HEIGHT_BASE;
|
||||
}
|
||||
|
||||
var amountScale = (amountHeight / AMOUNT_HEIGHT_BASE);
|
||||
if (amountScale < 0.5) {
|
||||
amountScale = 0.5;
|
||||
}
|
||||
if (amountScale > 1.1) {
|
||||
amountScale = 1.1;
|
||||
}
|
||||
|
||||
var s = amountScale;
|
||||
|
||||
// Make space for the balance button when it needs to display.
|
||||
var TOP_NO_BALANCE_BUTTON = 115;
|
||||
var TOP_BALANCE_BUTTON = 30;
|
||||
var top = TOP_NO_BALANCE_BUTTON;
|
||||
if ($scope.showBalanceButton) {
|
||||
top = TOP_BALANCE_BUTTON;
|
||||
}
|
||||
|
||||
var amountTop = ((amountScale - 0.80) / 0.80) * top;
|
||||
if (amountTop < -2) {
|
||||
amountTop = -2;
|
||||
}
|
||||
if (amountTop > top) {
|
||||
amountTop = top;
|
||||
}
|
||||
|
||||
var t = amountTop;
|
||||
|
||||
$scope.altAmountOpacity = (amountHeight - 100) / 80;
|
||||
$scope.buttonsOpacity = (amountHeight - 140) / 70;
|
||||
$window.requestAnimationFrame(function() {
|
||||
$scope.amountHeight = amountHeight + 'px';
|
||||
$scope.contentMargin = contentMargin + 'px';
|
||||
$scope.amountScale = 'scale3d(' + s + ',' + s + ',' + s + ') translateY(' + t + 'px)';
|
||||
$scope.$digest();
|
||||
getScrollPosition();
|
||||
});
|
||||
$scope.scrollPosition = pos;
|
||||
}
|
||||
|
||||
var scrollWatcherInitialized;
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
if ($scope.isCordova && $scope.isAndroid) setAndroidStatusBarColor();
|
||||
if (scrollWatcherInitialized || !$scope.amountIsCollapsible) {
|
||||
return;
|
||||
}
|
||||
scrollWatcherInitialized = true;
|
||||
});
|
||||
|
||||
|
|
@ -370,7 +380,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
if (!$scope.wallet) return;
|
||||
$scope.requiresMultipleSignatures = $scope.wallet.credentials.m > 1;
|
||||
|
||||
$scope.updatingTxHistory = true;
|
||||
$scope.vm.gettingInitialHistory = true;
|
||||
|
||||
addressbookService.list(function(err, ab) {
|
||||
if (err) $log.error(err);
|
||||
|
|
@ -380,21 +390,25 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
listeners = [
|
||||
$rootScope.$on('bwsEvent', function(e, walletId) {
|
||||
if (walletId == $scope.wallet.id && e.type != 'NewAddress')
|
||||
$scope.updateAll();
|
||||
$scope.updateAll(false, false);
|
||||
}),
|
||||
$rootScope.$on('Local/TxAction', function(e, walletId) {
|
||||
if (walletId == $scope.wallet.id)
|
||||
$scope.updateAll();
|
||||
$scope.updateAll(false, false);
|
||||
}),
|
||||
];
|
||||
});
|
||||
|
||||
var refreshInterval;
|
||||
|
||||
$scope.$on("$ionicView.afterEnter", function(event, data) {
|
||||
$scope.updateAll();
|
||||
refreshAmountSection();
|
||||
$scope.$on("$ionicView.afterEnter", function onAfterEnter(event, data) {
|
||||
updateTxHistoryFromCachedData();
|
||||
$scope.updateAll(true, true);
|
||||
// refreshAmountSection();
|
||||
refreshInterval = $interval($scope.onRefresh, 10 * 1000);
|
||||
$timeout(function() {
|
||||
getScrollPosition();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.afterLeave", function(event, data) {
|
||||
|
|
|
|||
|
|
@ -1,189 +1,204 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('walletSelectorController', function($scope, $state, sendFlowService, configService, gettextCatalog, profileService, txFormatService) {
|
||||
(function () {
|
||||
|
||||
var fromWalletId = '';
|
||||
var priceDisplayAsFiat = false;
|
||||
var unitDecimals = 0;
|
||||
var unitsFromSatoshis = 0;
|
||||
angular
|
||||
.module('copayApp.controllers')
|
||||
.controller('walletSelectorController', walletSelectorController);
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
|
||||
$scope.$on("$ionicView.enter", onEnter);
|
||||
|
||||
function onBeforeEnter(event, data) {
|
||||
if (data.direction == "back") {
|
||||
sendFlowService.state.pop();
|
||||
}
|
||||
function walletSelectorController ($scope, $state, sendFlowService, configService, gettextCatalog, ongoingProcess, profileService, walletService, txFormatService) {
|
||||
var fromWalletId = '';
|
||||
var priceDisplayAsFiat = false;
|
||||
var unitDecimals = 0;
|
||||
var unitsFromSatoshis = 0;
|
||||
|
||||
$scope.params = sendFlowService.state.getClone();
|
||||
|
||||
console.log('walletSelector onBeforeEnter after back sendflow', $scope.params);
|
||||
|
||||
var config = configService.getSync().wallet.settings;
|
||||
priceDisplayAsFiat = config.priceDisplay === 'fiat';
|
||||
unitDecimals = config.unitDecimals;
|
||||
unitsFromSatoshis = 1 / config.unitToSatoshi;
|
||||
|
||||
if ($scope.params.isWalletTransfer) {
|
||||
$scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
|
||||
} else if (!$scope.params.thirdParty) {
|
||||
$scope.sendFlowTitle = gettextCatalog.getString('Send');
|
||||
}
|
||||
|
||||
$scope.coin = false; // Wallets to show (for destination screen or contacts)
|
||||
$scope.type = $scope.params['fromWalletId'] ? 'destination' : 'origin'; // origin || destination
|
||||
fromWalletId = $scope.params['fromWalletId'];
|
||||
|
||||
if ($scope.type === 'destination' && $scope.params.toAddress) {
|
||||
$state.transitionTo(getNextStep($scope.params));
|
||||
}
|
||||
|
||||
if ($scope.params.coin) {
|
||||
$scope.coin = $scope.params.coin; // Contacts have a coin embedded
|
||||
}
|
||||
|
||||
if ($scope.params.amount) { // There is an amount, so presume that it is a payment request
|
||||
$scope.sendFlowTitle = gettextCatalog.getString('Payment Request');
|
||||
$scope.specificAmount = $scope.specificAlternativeAmount = '';
|
||||
$scope.isPaymentRequest = true;
|
||||
}
|
||||
if ($scope.params.thirdParty) {
|
||||
$scope.thirdParty = $scope.params.thirdParty;
|
||||
}
|
||||
};
|
||||
|
||||
function onEnter (event, data) {
|
||||
configService.whenAvailable(function(config) {
|
||||
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
|
||||
});
|
||||
|
||||
if ($scope.thirdParty) {
|
||||
// Third party services specific logic
|
||||
handleThirdPartyIfShapeshift();
|
||||
}
|
||||
|
||||
prepareWalletLists();
|
||||
formatRequestedAmount();
|
||||
};
|
||||
|
||||
function formatRequestedAmount() {
|
||||
if ($scope.params.amount) {
|
||||
var cryptoAmount = (unitsFromSatoshis * $scope.params.amount).toFixed(unitDecimals);
|
||||
var cryptoCoin = $scope.coin.toUpperCase();
|
||||
|
||||
txFormatService.formatAlternativeStr($scope.coin, $scope.params.amount, function onFormatAlternativeStr(formatted){
|
||||
if (formatted) {
|
||||
var fiatParts = formatted.split(' ');
|
||||
var fiatAmount = fiatParts[0];
|
||||
var fiatCurrrency = fiatParts.length > 1 ? fiatParts[1] : '';
|
||||
|
||||
if (priceDisplayAsFiat) {
|
||||
$scope.requestAmount = fiatAmount;
|
||||
$scope.requestCurrency = fiatCurrrency;
|
||||
|
||||
$scope.requestAmountSecondary = cryptoAmount;
|
||||
$scope.requestCurrencySecondary = cryptoCoin;
|
||||
} else {
|
||||
$scope.requestAmount = cryptoAmount;
|
||||
$scope.requestCurrency = cryptoCoin;
|
||||
|
||||
$scope.requestAmountSecondary = fiatAmount;
|
||||
$scope.requestCurrencySecondary = fiatCurrrency;
|
||||
}
|
||||
$scope.$apply();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleThirdPartyIfShapeshift() {
|
||||
console.log($scope.thirdParty, $scope.coin);
|
||||
if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the
|
||||
$scope.coin = profileService.getWallet(fromWalletId).coin;
|
||||
if ($scope.coin === 'bch') {
|
||||
$scope.coin = 'btc';
|
||||
} else {
|
||||
$scope.coin = 'bch';
|
||||
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
|
||||
$scope.$on("$ionicView.enter", onEnter);
|
||||
|
||||
function onBeforeEnter(event, data) {
|
||||
if (data.direction == "back") {
|
||||
sendFlowService.state.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function prepareWalletLists() {
|
||||
var walletsAll = [];
|
||||
var walletsSufficientFunds = [];
|
||||
$scope.walletsInsufficientFunds = []; // For origin screen
|
||||
$scope.params = sendFlowService.state.getClone();
|
||||
|
||||
if ($scope.type === 'origin') {
|
||||
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send from');
|
||||
console.log('walletSelector onBeforeEnter after back sendflow', $scope.params);
|
||||
|
||||
var config = configService.getSync().wallet.settings;
|
||||
priceDisplayAsFiat = config.priceDisplay === 'fiat';
|
||||
unitDecimals = config.unitDecimals;
|
||||
unitsFromSatoshis = 1 / config.unitToSatoshi;
|
||||
|
||||
if ($scope.params.isWalletTransfer) {
|
||||
$scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
|
||||
} else if (!$scope.params.thirdParty) {
|
||||
$scope.sendFlowTitle = gettextCatalog.getString('Send');
|
||||
}
|
||||
|
||||
$scope.coin = false; // Wallets to show (for destination screen or contacts)
|
||||
$scope.type = $scope.params['fromWalletId'] ? 'destination' : 'origin'; // origin || destination
|
||||
fromWalletId = $scope.params['fromWalletId'];
|
||||
|
||||
if ($scope.type === 'destination' && $scope.params.toAddress) {
|
||||
$state.transitionTo(getNextStep($scope.params));
|
||||
}
|
||||
|
||||
if ($scope.params.coin) {
|
||||
$scope.coin = $scope.params.coin; // Contacts have a coin embedded
|
||||
}
|
||||
|
||||
if ($scope.params.amount) { // There is an amount, so presume that it is a payment request
|
||||
$scope.sendFlowTitle = gettextCatalog.getString('Payment Request');
|
||||
$scope.specificAmount = $scope.specificAlternativeAmount = '';
|
||||
$scope.isPaymentRequest = true;
|
||||
}
|
||||
if ($scope.params.thirdParty) {
|
||||
$scope.thirdParty = $scope.params.thirdParty;
|
||||
}
|
||||
};
|
||||
|
||||
function onEnter (event, data) {
|
||||
configService.whenAvailable(function(config) {
|
||||
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
|
||||
});
|
||||
|
||||
if ($scope.thirdParty) {
|
||||
// Third party services specific logic
|
||||
handleThirdPartyIfShapeshift();
|
||||
}
|
||||
|
||||
prepareWalletLists();
|
||||
formatRequestedAmount();
|
||||
};
|
||||
|
||||
function formatRequestedAmount() {
|
||||
if ($scope.params.amount) {
|
||||
var cryptoAmount = (unitsFromSatoshis * $scope.params.amount).toFixed(unitDecimals);
|
||||
var cryptoCoin = $scope.coin.toUpperCase();
|
||||
|
||||
walletsAll = profileService.getWallets({coin: $scope.coin});
|
||||
txFormatService.formatAlternativeStr($scope.coin, $scope.params.amount, function onFormatAlternativeStr(formatted){
|
||||
if (formatted) {
|
||||
var fiatParts = formatted.split(' ');
|
||||
var fiatAmount = fiatParts[0];
|
||||
var fiatCurrrency = fiatParts.length > 1 ? fiatParts[1] : '';
|
||||
|
||||
if (priceDisplayAsFiat) {
|
||||
$scope.requestAmount = fiatAmount;
|
||||
$scope.requestCurrency = fiatCurrrency;
|
||||
|
||||
$scope.requestAmountSecondary = cryptoAmount;
|
||||
$scope.requestCurrencySecondary = cryptoCoin;
|
||||
} else {
|
||||
$scope.requestAmount = cryptoAmount;
|
||||
$scope.requestCurrency = cryptoCoin;
|
||||
|
||||
$scope.requestAmountSecondary = fiatAmount;
|
||||
$scope.requestCurrencySecondary = fiatCurrrency;
|
||||
}
|
||||
$scope.$apply();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleThirdPartyIfShapeshift() {
|
||||
console.log($scope.thirdParty, $scope.coin);
|
||||
if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the
|
||||
$scope.coin = profileService.getWallet(fromWalletId).coin;
|
||||
if ($scope.coin === 'bch') {
|
||||
$scope.coin = 'btc';
|
||||
} else {
|
||||
$scope.coin = 'bch';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function prepareWalletLists() {
|
||||
var walletsAll = [];
|
||||
var walletsSufficientFunds = [];
|
||||
$scope.walletsInsufficientFunds = []; // For origin screen
|
||||
|
||||
if ($scope.type === 'origin') {
|
||||
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send from');
|
||||
|
||||
if ($scope.params.amount || $scope.coin) {
|
||||
|
||||
walletsAll = profileService.getWallets({coin: $scope.coin});
|
||||
ongoingProcess.set('scanning', true);
|
||||
walletsAll.forEach(function forWallet(wallet) {
|
||||
if (!wallet.status && !wallet.cachedStatus) {
|
||||
walletService.getStatus(wallet, {}, function(err, status) {
|
||||
wallet.status = status;
|
||||
if (status.availableBalanceSat > ($scope.params.amount ? $scope.params.amount : 0)) {
|
||||
walletsSufficientFunds.push(wallet);
|
||||
} else {
|
||||
$scope.walletsInsufficientFunds.push(wallet);
|
||||
}
|
||||
if ($scope.coin === 'btc') { // As this is a promise
|
||||
$scope.walletsBtc = walletsSufficientFunds;
|
||||
} else {
|
||||
$scope.walletsBch = walletsSufficientFunds;
|
||||
}
|
||||
ongoingProcess.set('scanning', false);
|
||||
});
|
||||
} else {
|
||||
var walletStatus = null;
|
||||
if (wallet.status && wallet.status.isValid) {
|
||||
walletStatus = wallet.status;
|
||||
} else if (wallet.cachedStatus && wallet.status.isValid) {
|
||||
walletStatus = wallet.cachedStatus;
|
||||
}
|
||||
|
||||
if (walletStatus && walletStatus.availableBalanceSat > ($scope.params.amount ? $scope.params.amount : 0)) {
|
||||
walletsSufficientFunds.push(wallet);
|
||||
} else {
|
||||
$scope.walletsInsufficientFunds.push(wallet);
|
||||
}
|
||||
ongoingProcess.set('scanning', false);
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.coin === 'btc') {
|
||||
$scope.walletsBtc = walletsSufficientFunds;
|
||||
} else {
|
||||
$scope.walletsBch = walletsSufficientFunds;
|
||||
}
|
||||
} else {
|
||||
$scope.walletsBch = profileService.getWallets({coin: 'bch', hasFunds: true});
|
||||
$scope.walletsBtc = profileService.getWallets({coin: 'btc', hasFunds: true});
|
||||
$scope.walletsInsufficientFunds = profileService.getWallets({coin: $scope.coin, hasNoFunds: true});
|
||||
}
|
||||
|
||||
walletsAll.forEach(function forWallet(wallet){
|
||||
if (wallet.status.availableBalanceSat > $scope.params.amount) {
|
||||
walletsSufficientFunds.push(wallet);
|
||||
} else {
|
||||
$scope.walletsInsufficientFunds.push(wallet);
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.coin === 'btc') {
|
||||
$scope.walletsBtc = walletsSufficientFunds;
|
||||
} else {
|
||||
$scope.walletsBch = walletsSufficientFunds;
|
||||
} else if ($scope.type === 'destination') {
|
||||
if (!$scope.coin) { // Allow for the coin to be set by a third party
|
||||
$scope.fromWallet = profileService.getWallet(fromWalletId);
|
||||
$scope.coin = $scope.fromWallet.coin; // Only show wallets with the select origin wallet coin
|
||||
}
|
||||
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send to');
|
||||
|
||||
} else if ($scope.coin) {
|
||||
walletsAll = profileService.getWallets({coin: $scope.coin});
|
||||
walletsAll.forEach(function forWallet(wallet){
|
||||
if (wallet.status.availableBalanceSat > 0) {
|
||||
walletsSufficientFunds.push(wallet);
|
||||
} else {
|
||||
$scope.walletsInsufficientFunds.push(wallet);
|
||||
}
|
||||
});
|
||||
|
||||
if ($scope.coin === 'btc') {
|
||||
$scope.walletsBtc = walletsSufficientFunds;
|
||||
if ($scope.coin === 'btc') { // if no specific coin is set or coin is set btc
|
||||
$scope.walletsBtc = profileService.getWallets({coin: $scope.coin});
|
||||
} else {
|
||||
$scope.walletsBch = walletsSufficientFunds;
|
||||
$scope.walletsBch = profileService.getWallets({coin: $scope.coin});
|
||||
}
|
||||
} else {
|
||||
$scope.walletsBch = profileService.getWallets({coin: 'bch', hasFunds: true});
|
||||
$scope.walletsBtc = profileService.getWallets({coin: 'btc', hasFunds: true});
|
||||
$scope.walletsInsufficientFunds = profileService.getWallets({coin: $scope.coin, hasNoFunds: true});
|
||||
}
|
||||
|
||||
} else if ($scope.type === 'destination') {
|
||||
if (!$scope.coin) { // Allow for the coin to be set by a third party
|
||||
$scope.fromWallet = profileService.getWallet(fromWalletId);
|
||||
$scope.coin = $scope.fromWallet.coin; // Only show wallets with the select origin wallet coin
|
||||
}
|
||||
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send to');
|
||||
|
||||
if ($scope.coin === 'btc') { // if no specific coin is set or coin is set btc
|
||||
$scope.walletsBtc = profileService.getWallets({coin: $scope.coin});
|
||||
} else {
|
||||
$scope.walletsBch = profileService.getWallets({coin: $scope.coin});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$scope.useWallet = function(wallet) {
|
||||
var params = sendFlowService.state.getClone();
|
||||
if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from
|
||||
params.fromWalletId = wallet.id;
|
||||
} else { // we're on the destination screen, set wallet to send to
|
||||
params.toWalletId = wallet.id;
|
||||
$scope.useWallet = function(wallet) {
|
||||
var params = sendFlowService.state.getClone();
|
||||
if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from
|
||||
params.fromWalletId = wallet.id;
|
||||
} else { // we're on the destination screen, set wallet to send to
|
||||
params.toWalletId = wallet.id;
|
||||
}
|
||||
sendFlowService.goNext(params);
|
||||
};
|
||||
|
||||
$scope.goBack = function() {
|
||||
sendFlowService.router.goBack();
|
||||
}
|
||||
sendFlowService.goNext(params);
|
||||
};
|
||||
|
||||
$scope.goBack = function() {
|
||||
sendFlowService.router.goBack();
|
||||
}
|
||||
|
||||
});
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue