Merge pull request #268 from Bitcoin-com/wallet/sprint/20

Wallet/sprint/20
This commit is contained in:
Jean-Baptiste Dominguez 2018-08-13 15:33:24 +09:00 committed by GitHub
commit b25879b251
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 503 additions and 301 deletions

View file

@ -29,6 +29,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
vm.finish = finish;
vm.goBack = goBack;
vm.loadMore = loadMore;
vm.next = next;
vm.openPopup = openPopup;
vm.pushDigit = pushDigit;
vm.removeDigit = removeDigit;
@ -66,15 +67,14 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
}
function onBeforeEnter(event, data) {
console.log('amount onBeforeEnter sendflow ', sendFlowService.getState());
if (data.direction == "back") {
sendFlowService.popState();
}
console.log('amount onBeforeEnter after back sendflow ', sendFlowService.state);
initCurrencies();
passthroughParams = sendFlowService;
passthroughParams = sendFlowService.getStateClone();
vm.fromWalletId = passthroughParams.fromWalletId;
vm.toWalletId = passthroughParams.toWalletId;
@ -463,7 +463,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
};
if (vm.thirdParty) {
confirmData['thirdParty'] = this.thirdParty;
confirmData.thirdParty = vm.thirdParty;
}
sendFlowService.pushState(confirmData);
@ -478,7 +478,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
// Currency
var next = 10;
var nextCurrencies = 10;
var completeAlternativeList = [];
var popularCurrencyList = [
@ -537,12 +537,17 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
function loadMore() {
$timeout(function() {
vm.altCurrencyList = completeAlternativeList.slice(0, next);
next += 10;
vm.altCurrencyList = completeAlternativeList.slice(0, nextCurrencies);
nextCurrencies += 10;
vm.listComplete = vm.altCurrencyList.length >= completeAlternativeList.length;
$scope.$broadcast('scroll.infiniteScrollComplete');
}, 100);
};
}
function next() {
useSendMax = false;
vm.finish();
}
function findCurrency(search) {
if (!search) initCurrencies();

View file

@ -75,9 +75,9 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
function onBeforeEnter(event, data) {
console.log('walletSelector onBeforeEnter sendflow ', sendFlowService.getState());
console.log('walletSelector onBeforeEnter sendflow ', sendFlowService.state);
defaults = configService.getDefaults();
sendFlowData = sendFlowService.getState();
sendFlowData = sendFlowService.getStateClone();
originWalletId = sendFlowData.fromWalletId;
satoshis = parseInt(sendFlowData.amount, 10);
toAddress = sendFlowData.toAddress;
@ -116,7 +116,9 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
if (!tx || !vm.originWallet) return;
if (vm.paymentExpired) {
popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.'));
popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.', function () {
$ionicHistory.goBack();
}));
vm.sendStatus = '';
$timeout(function() {
$scope.$apply();
@ -223,7 +225,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
// Grab stateParams
tx = {
amount: parseInt(sendFlowData.amount),
sendMax: sendFlowData.sendMax === 'true' ? true : false,
sendMax: sendFlowData.sendMax,
fromWalletId: sendFlowData.fromWalletId,
toAddress: sendFlowData.toAddress,
paypro: txPayproData,
@ -486,20 +488,26 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
walletService.getAddress(vm.originWallet, false, function onReturnWalletAddress(err, returnAddr) {
if (err) {
ongoingProcess.set('connectingShapeshift', false);
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString());
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () {
$ionicHistory.goBack();
});
return;
}
walletService.getAddress(toWallet, false, function onWithdrawalWalletAddress(err, withdrawalAddr) {
if (err) {
ongoingProcess.set('connectingShapeshift', false);
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString());
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () {
$ionicHistory.goBack();
});
return;
}
shapeshiftService.shiftIt(vm.originWallet.coin, toWallet.coin, withdrawalAddr, returnAddr, function onShiftIt(err, shapeshiftData) {
if (err && err != null) {
ongoingProcess.set('connectingShapeshift', false);
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString());
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () {
$ionicHistory.goBack();
});
} else {
vm.memo = 'ShapeShift Order:\nhttps://www.shapeshift.io/#/status/' + shapeshiftData.orderId;
vm.memoExpanded = !!vm.memo;
@ -640,7 +648,9 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
$timeout(function() {
$scope.$apply();
});
popupService.showAlert(gettextCatalog.getString('Error at confirm'), bwcError.msg(msg));
popupService.showAlert(gettextCatalog.getString('Error at confirm'), bwcError.msg(msg), function () {
$ionicHistory.goBack();
});
};
function setupTx(tx) {
@ -825,7 +835,9 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
if (tx.sendMax && sendMaxInfo.amount == 0) {
ongoingProcess.set('calculatingFee', false);
setNotReady(gettextCatalog.getString('Insufficient confirmed funds'));
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'));
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'), function () {
$ionicHistory.goBack();
});
return cb('no_funds');
}

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('tabHomeController',
function($rootScope, sendFlowService, $timeout, $scope, $state, $stateParams, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, bannerService, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, startupService, addressbookService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService, pushNotificationsService, timeService, $ionicNavBarDelegate) {
function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, bannerService, communityService, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, sendFlowService, storageService, txpModalService, appConfigService, startupService, addressbookService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService, pushNotificationsService, timeService, bitcoincomService, pricechartService, firebaseEventsService, servicesService, shapeshiftService, $ionicNavBarDelegate, signVerifyMessageService) {
var wallet;
var listeners = [];
var notifications = [];
@ -58,7 +58,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
});
}
};
function onEnter(event, data) {
$ionicNavBarDelegate.showBar(true);
updateAllWallets();
@ -214,6 +214,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
var j = 0;
lodash.each(wallets, function(wallet) {
walletService.invalidateCache(wallet); // Temporary solution, to have the good balance, when we ask to reload the wallets.
walletService.getStatus(wallet, {}, function(err, status) {
if (err) {

View file

@ -1,6 +1,6 @@
'use strict';
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, txFormatService, soundService, clipboardService) {
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 listeners = [];
$scope.bchAddressType = { type: 'cashaddr' };
@ -18,9 +18,10 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.displayBalanceAsFiat = true;
$scope.requestSpecificAmount = function() {
$state.go('tabs.paymentRequest.amount', {
sendFlowService.pushState({
toWalletId: $scope.wallet.credentials.walletId
});
$state.go('tabs.paymentRequest.amount');
};
$scope.setAddress = function(newAddr, copyAddress) {
@ -158,6 +159,10 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
soundService.play('misc/payment_received.mp3');
}
// Notify new tx
$scope.$emit('bwsEvent', $scope.wallet.id);
$scope.$apply(function () {
$scope.showingPaymentReceived = true;
});

View file

@ -28,14 +28,15 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
};
$scope.$on("$ionicView.enter", function(event, data) {
var stateParams = sendFlowService.getStateClone();
$scope.fromWallet = profileService.getWallet(stateParams.fromWalletId);
clipboardService.readFromClipboard(function(text) {
if (text.length > 200) {
text = text.substring(0, 200);
}
var stateParams = sendFlowService.getState();
$scope.fromWallet = profileService.getWallet(stateParams.fromWalletId);
$scope.clipboardHasAddress = false;
$scope.clipboardHasContent = false;
if ((text.indexOf('bitcoincash:') === 0 || text[0] === 'C' || text[0] === 'H' || text[0] === 'p' || text[0] === 'q') && text.replace('bitcoincash:', '').length === 42) { // CashAddr
@ -183,7 +184,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
$log.debug('Got toAddress:' + toAddress + ' | ' + item.name);
var stateParams = sendFlowService.getState();
var stateParams = sendFlowService.getStateClone();
stateParams.toAddress = toAddress,
stateParams.coin = item.coin;
sendFlowService.pushState(stateParams);
@ -199,7 +200,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
$scope.startWalletToWalletTransfer = function() {
console.log('startWalletToWalletTransfer()');
var params = sendFlowService.getState();
var params = sendFlowService.getStateClone();
sendFlowService.pushState(params);
$state.transitionTo('tabs.send.wallet-to-wallet', {
fromWalletId: sendFlowService.fromWalletId
@ -221,7 +222,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
$scope.$on("$ionicView.beforeEnter", function(event, data) {
console.log(data);
console.log('tab-send onBeforeEnter sendflow ', sendFlowService.getState());
console.log('tab-send onBeforeEnter sendflow ', sendFlowService.state);
$scope.isIOS = platformInfo.isIOS && platformInfo.isCordova;
$scope.showWalletsBch = $scope.showWalletsBtc = $scope.showWallets = false;

View file

@ -304,6 +304,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
};
function refreshAmountSection(scrollPos) {
var AMOUNT_HEIGHT_BASE = 270;
$scope.showBalanceButton = false;
if ($scope.status) {
$scope.showBalanceButton = ($scope.status.totalBalanceSat != $scope.status.spendableAmount);
@ -315,16 +316,16 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
}
scrollPos = scrollPos || 0;
var amountHeight = 210 - scrollPos;
var amountHeight = AMOUNT_HEIGHT_BASE - scrollPos;
if (amountHeight < 80) {
amountHeight = 80;
}
var contentMargin = amountHeight;
if (contentMargin > 210) {
contentMargin = 210;
if (contentMargin > AMOUNT_HEIGHT_BASE) {
contentMargin = AMOUNT_HEIGHT_BASE;
}
var amountScale = (amountHeight / 210);
var amountScale = (amountHeight / AMOUNT_HEIGHT_BASE);
if (amountScale < 0.5) {
amountScale = 0.5;
}

View file

@ -11,13 +11,12 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
$scope.$on("$ionicView.enter", onEnter);
function onBeforeEnter(event, data) {
console.log('walletSelector onBeforeEnter sendflow', sendFlowService.getState());
if (data.direction == "back") {
sendFlowService.popState();
}
console.log('walletSelector onBeforeEnter after back sendflow', sendFlowService.state);
var stateParams = sendFlowService.getState();
$scope.params = sendFlowService.getStateClone();
var config = configService.getSync().wallet.settings;
priceDisplayAsFiat = config.priceDisplay === 'fiat';
@ -29,21 +28,23 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
$scope.sendFlowTitle = gettextCatalog.getString('Wallet to Wallet Transfer');
break;
case 'tabs.send.destination':
if (stateParams.fromWalletId) {
if ($scope.params.fromWalletId && !$scope.params.thirdParty) {
$scope.sendFlowTitle = gettextCatalog.getString('Wallet to Wallet Transfer');
}
break;
default:
if (!$scope.params.thirdParty) {
$scope.sendFlowTitle = gettextCatalog.getString('Send');
}
// nop
}
$scope.params = sendFlowService;
$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());
$state.transitionTo(getNextStep($scope.params));
}
if ($scope.params.coin) {
@ -103,13 +104,10 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
}
}
function getNextStep() {
if ($scope.thirdParty) {
$scope.params.thirdParty = $scope.thirdParty
}
if (!$scope.params.toWalletId && !$scope.params.toAddress) { // If we have no toAddress or fromWallet
function getNextStep(params) {
if (!params.toWalletId && !params.toAddress) { // If we have no toAddress or fromWallet
return 'tabs.send.destination';
} else if (!$scope.params.amount) { // If we have no amount
} else if (!params.amount) { // If we have no amount
return 'tabs.send.amount';
} else { // If we do have them
return 'tabs.send.review';
@ -193,14 +191,16 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
$scope.useWallet = function(wallet) {
var params = sendFlowService.getState();
var params = sendFlowService.getStateClone();
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.pushState(params);
$state.transitionTo(getNextStep(), $scope.params);
var nextStep = getNextStep(params);
console.log('walletSelector nextStep', nextStep);
$state.transitionTo(nextStep, $scope.params);
};
$scope.goBack = function() {

View file

@ -1,5 +1,6 @@
'use strict';
(function(){
/**
* @desc amount directive that can be used to display formatted financial values
* size-equal attribute is optional, defaults to false.
@ -10,168 +11,189 @@
* @example <formatted-amount value="fee.value" currency="fee.currency"></formatted-amount>
* @example <formatted-amount value="fee.value" currency="fee.currency" size-equal="true"></formatted-amount>
*/
angular.module('bitcoincom.directives')
.directive('formattedAmount', function(uxLanguage) {
return {
restrict: 'E',
scope: {
value: '@',
currency: '@',
sizeEqual: '@'
},
templateUrl: 'views/includes/formatted-amount.html',
controller: function($scope, $timeout) {
$scope.canShow = false;
$scope.displaySizeEqual = !!$scope.sizeEqual;
$timeout(function onFormattedAmountTimeout() {
var decimalPlaces = {
'0': ['BIF', 'CLP', 'DJF', 'GNF', 'ILS', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'],
'3': ['BHD', 'IQD', 'JOD', 'KWD', 'OMR', 'TND'],
'8': ['BCH', 'BTC']
};
var localizeNumbers = function(x, minimumFractionDigits) {
var parsed = parseFloat(x);
var opts = {
minimumFractionDigits: minimumFractionDigits,
useGrouping: true
};
var lang = uxLanguage.getCurrentLanguage();
var localized = parsed.toLocaleString(lang, opts);
var corrected = ensureEnoughFractionalDigits(localized, x, minimumFractionDigits);
return corrected;
};
var buildAmount = function(start, middle, end) {
$scope.start = start;
$scope.middle = middle;
$scope.end = end;
};
var getDecimalPlaces = function(currency) {
if (decimalPlaces['0'].indexOf(currency.toUpperCase()) > -1) return '0';
if (decimalPlaces['3'].indexOf(currency.toUpperCase()) > -1) return '3';
if (decimalPlaces['8'].indexOf(currency.toUpperCase()) > -1) return '8';
return '2';
};
var getDecimalSeparator = function() {
var testNum = 1.5;
var testString = testNum.toLocaleString(uxLanguage.getCurrentLanguage());
// Some environments let you set decimal separators that are more than one character
var separator = /^1(.+)5$/.exec(testString)[1]
return separator;
};
var formatNumbers = function() {
// During watch, may be changed from having a separate currency value,
// to both being in value. Don't want to use previous currency value.
// Try to extract currency from value..
var currencySplit = $scope.value.split(" ");
if (currencySplit.length === 2) {
$scope.currency = currencySplit[1];
}
$scope.currency = $scope.currency || '';
var parsed = parseFloat($scope.value);
var valueFormatted = '';
var valueProcessing = '';
switch (getDecimalPlaces($scope.currency)) {
case '0':
if (isNaN(parsed)) {
buildAmount('-', '', '');
} else {
valueFormatted = localizeNumbers(Math.round(parsed), 0);
buildAmount(valueFormatted, '', '');
}
break;
case '3':
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '---', '', '');
} else {
valueProcessing = parsed.toFixed(3);
valueFormatted = localizeNumbers(valueProcessing, 3);
buildAmount(valueFormatted, '', '');
}
break;
case '8':
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '---', '', '');
} else if (parsed === 0) {
buildAmount('0', '', '');
} else {
valueFormatted = parsed.toFixed(8);
valueFormatted = localizeNumbers(valueFormatted, 8);
var start = valueFormatted.slice(0, -5);
var middle = valueFormatted.slice(-5, -2);
var end = valueFormatted.substr(valueFormatted.length - 2);
buildAmount(start, middle, end);
}
break;
default: // 2
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '--', '', '');
} else {
valueProcessing = parseFloat(parsed.toFixed(2));
valueFormatted = localizeNumbers(valueProcessing, 2);
buildAmount(valueFormatted, '', '');
}
break;
}
$scope.canShow = true;
};
formatNumbers();
$scope.$watchGroup(['currency', 'value'], function onFormattedAmountWatch() {
formatNumbers();
});
/**
* On Android 4.4, toLocaleString() only returns 3 fractional digits when 8 is specified.
*/
function ensureEnoughFractionalDigits(localizedString, number, desiredFractionDigits) {
if (desiredFractionDigits === 0) {
// Assume it is OK
return localizedString;
}
var fractionalRe = /^(\d*\D)(\d+)$/;
var match = fractionalRe.exec(localizedString);
if (match.length !== 3) {
// Don't know what's happening, just return what we have
return localizedString;
}
var decimals = match[2];
var decimalCount = decimals.length;
if (decimalCount >= desiredFractionDigits) {
// Everything is OK.
return localizedString;
}
if (typeof number !== 'number') {
number = parseFloat(number);
}
var fixed = number.toFixed(desiredFractionDigits);
var fixedMatch = fractionalRe.exec(fixed);
if (fixedMatch.length !== 3) {
// Don't know what's happening, just return what we have
return localizedString;
}
// Keeps locale decimal separator.
var enough = match[1] + fixedMatch[2];
return enough;
}
});
angular
.module('bitcoincom.directives')
.directive('formattedAmount', function() {
return {
restrict: 'E',
scope: {
value: '@',
currency: '@',
sizeEqual: '@'
},
templateUrl: 'views/includes/formatted-amount.html',
controller: formattedAmountController
}
});
function formattedAmountController($scope, uxLanguage) {
$scope.vm = {};
var vm = $scope.vm;
vm.currency = '';
vm.value = '';
$scope.canShow = false
$scope.displaySizeEqual = !!$scope.sizeEqual;
var decimalPlaces = {
'0': ['BIF', 'CLP', 'DJF', 'GNF', 'ILS', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'],
'3': ['BHD', 'IQD', 'JOD', 'KWD', 'OMR', 'TND'],
'8': ['BCH', 'BTC']
};
$scope.$watch('value', function onFormattedAmountWatch() {
formatNumbers();
});
function buildAmount(start, middle, end) {
$scope.start = start;
$scope.middle = middle;
$scope.end = end;
};
/**
* On Android 4.4, toLocaleString() only returns 3 fractional digits when 8 is specified.
*/
function ensureEnoughFractionDigits(localizedString, number, desiredFractionDigits) {
if (desiredFractionDigits === 0) {
// Assume it is OK
return localizedString;
}
var fractionalRe = /^-*(\d*\D)(\d+)$/;
var match = fractionalRe.exec(localizedString);
if (!match || match.length !== 3) {
// Don't know what's happening, just return what we have
return localizedString;
}
var decimals = match[2];
var decimalCount = decimals.length;
if (decimalCount >= desiredFractionDigits) {
// Everything is OK.
return localizedString;
}
if (typeof number !== 'number') {
number = parseFloat(number);
}
var fixed = number.toFixed(desiredFractionDigits);
var fixedMatch = fractionalRe.exec(fixed);
if (!fixedMatch || fixedMatch.length !== 3) {
// Don't know what's happening, just return what we have
return localizedString;
}
// Keeps locale decimal separator.
var enough = match[1] + fixedMatch[2];
return enough;
}
function formatNumbers() {
// Might get "< 0.01 USD" being passed in.
// During watch, may be changed from having a separate currency value,
// to both being in value. Don't want to use previous currency value.
// Try to extract currency from value..
if (!$scope.currency || $scope.currency.length === 0) {
var currencySplit = $scope.value.split(" ");
if (currencySplit.length >= 2) {
vm.currency = currencySplit[currencySplit.length - 1];
}
} else {
vm.currency = $scope.currency;
}
// Redo this when we have proper formatting for low fees
if ($scope.value.indexOf("<") === 0) {
buildAmount($scope.value, '', '');
vm.currency = '';
$scope.canShow = true;
return;
}
// Remove thousands separators for parseFloat()
$scope.value = $scope.value.replace(',', '');
var parsed = parseFloat($scope.value);
var valueFormatted = '';
var valueProcessing = '';
switch (getDecimalPlaces(vm.currency)) {
case '0':
if (isNaN(parsed)) {
buildAmount('-', '', '');
} else {
valueFormatted = localizeNumbers(Math.round(parsed), 0);
buildAmount(valueFormatted, '', '');
}
break;
case '3':
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '---', '', '');
} else {
valueProcessing = parsed.toFixed(3);
valueFormatted = localizeNumbers(valueProcessing, 3);
buildAmount(valueFormatted, '', '');
}
break;
case '8':
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '---', '', '');
} else if (parsed === 0) {
buildAmount('0', '', '');
} else {
valueFormatted = parsed.toFixed(8);
valueFormatted = localizeNumbers(valueFormatted, 8);
var start = valueFormatted.slice(0, -5);
var middle = valueFormatted.slice(-5, -2);
var end = valueFormatted.substr(valueFormatted.length - 2);
buildAmount(start, middle, end);
}
break;
default: // 2
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '--', '', '');
} else {
valueProcessing = parseFloat(parsed.toFixed(2));
valueFormatted = localizeNumbers(valueProcessing, 2);
buildAmount(valueFormatted, '', '');
}
break;
}
$scope.canShow = true;
$scope.$apply();
};
function getDecimalPlaces(currency) {
if (decimalPlaces['0'].indexOf(currency.toUpperCase()) > -1) return '0';
if (decimalPlaces['3'].indexOf(currency.toUpperCase()) > -1) return '3';
if (decimalPlaces['8'].indexOf(currency.toUpperCase()) > -1) return '8';
return '2';
};
function getDecimalSeparator() {
var testNum = 1.5;
var testString = testNum.toLocaleString(uxLanguage.getCurrentLanguage());
// Some environments let you set decimal separators that are more than one character
var separator = /^1(.+)5$/.exec(testString)[1]
return separator;
};
function localizeNumbers(x, minimumFractionDigits) {
var parsed = parseFloat(x);
var opts = {
minimumFractionDigits: minimumFractionDigits,
useGrouping: true
};
var lang = uxLanguage.getCurrentLanguage();
var localized = parsed.toLocaleString(lang, opts);
var corrected = ensureEnoughFractionDigits(localized, x, minimumFractionDigits);
return corrected;
};
}
);
})();

View file

@ -0,0 +1,120 @@
'use strict';
(function(){
angular
.module('bitcoincom.directives')
.directive('walletBalance', function() {
return {
restrict: 'E',
scope: {
displayAsFiat: '@',
totalBalanceSat: '@',
// The Wallet object is sometimes not stringify()-able, so not interpolatable,
// so can't be passed to a directive.
walletStatus: '@',
walletCachedBalance: '@',
walletCachedBalanceUpdatedOn: '@',
walletCachedStatus: '@'
},
templateUrl: 'views/includes/wallet-balance.html',
controller: walletBalanceController
}
});
function walletBalanceController($log, $scope, txFormatService) {
var cryptoBalanceHasBeenDisplayed = false;
formatBalance();
$scope.$watchGroup(['displayAsFiat', 'totalBalanceSat'], function onWalletBalanceWatch() {
formatBalance();
});
function displayCryptoBalance(walletStatus, walletCachedBalance, walletCachedBalanceUpdatedOn, walletCachedStatus) {
console.log('displayCryptoBalance()');
if (walletStatus && walletStatus.isValid && walletStatus.totalBalanceStr) {
setDisplay(walletStatus.totalBalanceStr, '');
cryptoBalanceHasBeenDisplayed = true;
return;
}
if (walletCachedBalance) {
setDisplay(walletCachedBalance, walletCachedBalanceUpdatedOn);
return;
}
if (walletCachedStatus && walletCachedStatus.isValid && walletCachedStatus.totalBalanceStr) {
setDisplay(walletCachedStatus.totalBalanceStr, '');
return;
}
setDisplay('', '');
}
function displayFiatBalance(walletStatus, walletCachedStatus) {
var displayAmount = '';
if (walletStatus && walletStatus.isValid && walletStatus.alternativeBalanceAvailable) {
displayAmount = walletStatus.totalBalanceAlternative + ' ' + walletStatus.alternativeIsoCode;
setDisplay(displayAmount, '');
return;
}
if (walletCachedStatus && walletCachedStatus.isValid && walletCachedStatus.alternativeBalanceAvailable) {
displayAmount = walletCachedStatus.totalBalanceAlternative + ' ' + walletCachedStatus.alternativeIsoCode;
setDisplay(displayAmount, '');
return;
}
getFiatBalance(wallet);
}
function formatBalance() {
var displayAsFiat = $scope.displayAsFiat === 'true';
var walletStatusObj = null;
var walletCachedBalance = null;
var walletCachedBalanceUpdatedOn = null;
var walletCachedStatusObj = null;
try {
walletStatusObj = JSON.parse($scope.walletStatus);
} catch (e) {
$log.warn('Failed to parse walletStatus.', e);
}
try {
walletCachedStatusObj = JSON.parse($scope.walletCachedStatus);
} catch (e) {
$log.warn('Failed to parse walletCachedStatus.', e);
}
if (!displayAsFiat || displayAsFiat && !cryptoBalanceHasBeenDisplayed) {
displayCryptoBalance(walletStatusObj, walletCachedBalance, walletCachedBalanceUpdatedOn, walletCachedStatusObj);
}
if (displayAsFiat) {
displayFiatBalance(walletStatusObj, walletCachedStatusObj);
}
}
function getFiatBalance(wallet) {
if (!(wallet.status && wallet.status.isValid)) {
$log.warn('Abandoning call to get fiat balance, because no valid wallet status.');
return;
}
txFormatService.formatAlternativeStr(wallet.coin, wallet.status.totalBalanceSat, function onFormatAlernativeStr(formatted) {
if (formatted) {
setDisplay(formatted, '');
}
});
}
function setDisplay(amount, cachedBalanceUpdatedOn) {
$scope.displayAmount = amount;
$scope.cachedBalanceUpdatedOn = cachedBalanceUpdatedOn;
}
}
})();

View file

@ -1277,6 +1277,13 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
});
window.BitAnalytics.ActionHandlers.trackAction(actionTabOpen);
var actionShapeShiftStart = new window.BitAnalytics.ActionFactory.createAction('click', {
name: 'shapeshift_start_click',
class: 'track_shapeshift_start_click',
channels: [channel]
});
window.BitAnalytics.ActionHandlers.trackAction(actionShapeShiftStart);
// Init language
uxLanguage.init(function (lang) {

View file

@ -82,7 +82,7 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
});
// Timeout is required to enable the "Back" button
$timeout(function() {
var params = sendFlowService.getState();
var params = sendFlowService.getStateClone();
if (amount) {
params.amount = amount;
@ -447,7 +447,7 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
amount: thirdPartyData.amount,
toAddress: thirdPartyData.toAddress,
coin: coin,
thirdParty: JSON.stringify(thirdPartyData)
thirdParty: thirdPartyData
};
// fee
@ -455,6 +455,9 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
stateParams.requiredFeeRate = thirdPartyData.requiredFeeRate * 1024;
}
// This does not make sense, thirdPartyData gets added by stateParams below
//sendFlowService.pushState(thirdPartyData);
scannerService.pausePreview();
$state.go('tabs.send', {}, {
'reload': true,

View file

@ -9,17 +9,21 @@ angular
function sendFlowService($log) {
var service = {
amount: '',
fromWalletId: '',
sendMax: false,
thirdParty: null,
toAddress: '',
toWalletId: '',
// A separate state variable so we can ensure it is cleared of everything,
// even other properties added that this service does not know about. (such as "coin")
state: {
amount: '',
fromWalletId: '',
sendMax: false,
thirdParty: null,
toAddress: '',
toWalletId: ''
},
previousStates: [],
// Functions
clear: clear,
getState: getState,
getStateClone: getStateClone,
map: map,
popState: popState,
pushState: pushState,
@ -36,22 +40,24 @@ angular
function clearCurrent() {
console.log("sendFlow clearCurrent()");
service.amount = '';
service.fromWalletId = '';
service.sendMax = false;
service.thirdParty = null;
service.toAddress = '';
service.toWalletId = '';
service.state = {
amount: '',
fromWalletId: '',
sendMax: false,
thirdParty: null,
toAddress: '',
toWalletId: ''
}
}
/**
* Handy for debugging
*/
function getState() {
function getStateClone() {
var currentState = {};
Object.keys(service).forEach(function forCurrentParam(key) {
if (typeof service[key] !== 'function' && key !== 'previousStates') {
currentState[key] = service[key];
Object.keys(service.state).forEach(function forCurrentParam(key) {
if (typeof service.state[key] !== 'function' && key !== 'previousStates') {
currentState[key] = service.state[key];
}
});
return currentState;
@ -68,7 +74,7 @@ angular
function map(params) {
Object.keys(params).forEach(function forNewParam(key) {
service[key] = params[key];
service.state[key] = params[key];
});
};
@ -85,7 +91,7 @@ angular
function pushState(params) {
console.log('sendFlow push');
var currentParams = getState();
var currentParams = getStateClone();
service.previousStates.push(currentParams);
clearCurrent();
map(params);

View file

@ -1,7 +1,12 @@
'use strict'
angular.module('copayApp.services').factory('servicesService', function(configService, $log, lodash) {
var root = {};
var services = [];
var services = [{
name: 'shapeshift',
title: 'Shapeshift',
icon: 'icon-shapeshift',
sref: 'tabs.shapeshift',
}];
root.register = function(serviceInfo) {
$log.info('Adding Services entry:' + serviceInfo.name);

View file

@ -137,17 +137,5 @@ angular.module('copayApp.services').factory('shapeshiftService', function ($http
});
};
var servicesItem = {
name: 'shapeshift',
title: 'Shapeshift',
icon: 'icon-shapeshift',
sref: 'tabs.shapeshift',
};
var register = function() {
servicesService.register(servicesItem);
};
register();
return root;
});

View file

@ -74,7 +74,7 @@
color: #FFF;
}
&-outline {
@include button-style(transparent, #FFFFFF, #FAFAFA, #FFF, #FFFFFF);
@include button-style(transparent, #FFFFFF, #FFFFFF, #FFFFFF, #FFFFFF);
@include button-outline(#FFFFFF);
background: none;
box-shadow: none;

View file

@ -9,3 +9,4 @@
@import "expand-content";
@import "fee-summary";
@import "formatted-amount";
@import "wallet-balance";

View file

@ -0,0 +1,3 @@
.wallet-balance-directive {
display: inline-block;
}

View file

@ -305,7 +305,8 @@
&.very-long {
input, .unit, .primary-amount-display {
font-size: 0.9em;
font-size: 1.2em; // OK for iPhone 5 / SE with BCH to 8dp
@media (min-width: 375px) {
font-size: 1.3em;
@ -382,41 +383,46 @@
.available-funds {
color: #6F6F70;
text-align: left;
}
.change-currency {
text-align: right;
}
.warning {
color: $v-warning-color-2;
}
.extra,
button.extra {
/*display: flex;*/
flex: 0 1 auto;
}
button.extra {
background: none;
border: none;
color: #000;
font-family: 'ProximaNova';
font-size: 14px;
.extra {
flex: 1;
line-height: normal;
min-height: auto;
min-width: auto;
padding: 0;
}
.button .icon:before {
font-size: 14px;
line-height: normal;
}
.button {
background: none;
border: none;
border-radius: 0;
color: #000;
font-family: 'ProximaNova';
font-size: 14px;
line-height: normal;
min-height: auto;
min-width: auto;
padding: 0;
}
.button {
span {
display: flex;
align-items: center;
justify-content: center;
.button .icon:before {
font-size: 14px;
line-height: normal;
}
.button {
span {
display: flex;
align-items: center;
justify-content: center;
}
}
}
}

View file

@ -1,5 +1,4 @@
#view-review {
background-color: #494949;
slide-to-accept, slide-to-accept-success {
margin-bottom: constant(safe-area-inset-bottom); /* iOS 11.0 */

View file

@ -261,6 +261,7 @@
.no-alternative {
padding-top: 45px;
}
.item.item-footer {
font-weight: lighter;
}

View file

@ -15359,8 +15359,6 @@ log-options #check-bar .checkbox-icon {
#view-review .fee-summary {
position: absolute;
bottom: 92px; }
#view-review .fee-summary-spacer {
height: 15px; }
#view-review .shapeshift-banner, #view-review .bitpay-banner, #view-review .egifter-banner {
box-shadow: none; }
#view-review .warning {

View file

@ -14,14 +14,14 @@
<div class="send-amount-tool">
<div class="send-amount-tool-input amount">
<div class="primary-amount"
ng-class="{long: vm.amount.length > 5, 'very-long': vm.amount.length > 10}">
ng-class="{long: vm.amount.length > 5, 'very-long': vm.amount.length > 8}">
<span class="primary-amount-display text-selectable">
<formatted-amount value="{{vm.amount || '0'}}" currency="{{vm.unit}}"></formatted-amount>
{{vm.amount || '0'}} {{vm.unit}}
</span>
</div>
<span ng-show="vm.globalResult"><formatted-amount value="{{vm.globalResult}}" currency="{{vm.unit}}"></formatted-amount></span>
<div class="alternative-amount">
<span class="text-selectable"><formatted-amount value="{{vm.alternativeAmount || '0.00'}}" currency="{{vm.alternativeUnit}}"></formatted-amount></span>
<span class="text-selectable">{{vm.alternativeAmount || '0.00'}} {{vm.alternativeUnit}}</span>
</div>
<div class="switch-currencies" ng-click="vm.changeUnit()"><img src="img/icon-convert.svg"></div>
</div>
@ -34,17 +34,20 @@
</div>
<div class="send-amount-extras text-center">
<button class="extra button" ng-click="vm.openPopup()">
<span>
<img src="img/icon-alternative-currency-black.svg"/>
&ensp;
<span translate>Change Currency</span>
</span>
</button>
<div class="extra available-funds"
<div class="extra change-currency">
<button class="button" ng-click="vm.openPopup()">
<span>
<img src="img/icon-alternative-currency-black.svg"/>
<pre> </pre>
<span translate>Change Currency</span>
</span>
</button>
</div>
<div class="extra available-funds"
ng-class="{warning: vm.fundsAreInsufficient}"
ng-if="!vm.isRequestingSpecificAmount" translate>
<span>Available Funds:</span>&ensp;<span><formatted-amount value="{{vm.availableFunds}}" size-equal="true"></formatted-amount></span>
<span>Available Funds: </span><span><formatted-amount value="{{vm.availableFunds}}" size-equal="true"></formatted-amount></span>
</div>
</div>
</div>
</div>
@ -90,7 +93,7 @@
<button
class="button button-full button-primary no-margin"
ng-disabled="!vm.allowSend"
ng-click="vm.finish()"
ng-click="vm.next()"
style="position: absolute; bottom: 0;"
translate>
Next

View file

@ -32,15 +32,15 @@
</div>
<div ng-show="!showingPaymentReceived" class="amount">
<div ng-show="selectedPriceDisplay=='fiat'">
<span class="size-36">{{amountUnitStr}}</span>
<span class="size-36"><formatted-amount value="{{amountUnitStr}}"></formatted-amount></span>
<div class="size-14 amount-alternative">
{{altAmountStr | uppercase}}
<formatted-amount value="{{altAmountStr | uppercase}}"></formatted-amount>
</div>
</div>
<div ng-show="selectedPriceDisplay=='crypto'">
<span class="size-36">{{altAmountStr | uppercase}}</span>
<span class="size-36"><formatted-amount value="{{altAmountStr | uppercase}}"></formatted-amount></span>
<div class="size-14 amount-alternative">
{{amountUnitStr}}
<formatted-amount value="{{amountUnitStr}}"></formatted-amount>
</div>
</div>
</div>

View file

@ -1,4 +1,4 @@
<div class="formatted-amount"
ng-class="{ 'size-equal': displaySizeEqual }" ng-show="canShow">
<span ng-if="start.length > 0" class="start">{{start}}</span><span ng-if="middle.length > 0" class="middle">{{middle}}</span><span ng-if="end.length > 0" class="end">{{end}}</span><span ng-if="currency.length > 0" class="currency">{{currency}}</span>
<span ng-if="start.length > 0" class="start">{{start}}</span><span ng-if="middle.length > 0" class="middle">{{middle}}</span><span ng-if="end.length > 0" class="end">{{end}}</span><span ng-if="vm.currency.length > 0" class="currency">{{vm.currency}}</span>
</div>

View file

@ -24,7 +24,7 @@
(possible double spend)
</span>
<span ng-if="tx.action != 'invalid'">
{{tx.amountStr}}
<formatted-amount value={{tx.amountStr}}></formatted-amount>
</span>
</span>
<div>

View file

@ -0,0 +1,3 @@
<div class="wallet-balance-directive">
<formatted-amount value="{{displayAmount}}"></formatted-amount><span ng-if="age">{{&middot; (cachedBalanceUpdatedOn * 1000 | amTimeAgo)}}</span>
</div>

View file

@ -10,7 +10,7 @@
<div ng-if="notification.type == 'NewOutgoingTx'">
<span translate>Payment Sent </span>
<div class="wallet-activity-amount">
{{notification.amountStr}}
<formatted-amount value={{notification.amountStr}}
</div>
</div>
@ -19,7 +19,7 @@
<div ng-if="notification.type == 'NewIncomingTx'">
<span translate>Payment Received</span>
<div class="wallet-activity-amount">
{{notification.amountStr}}
<formatted-amount value={{notification.amountStr}}></formatted-amount>
</div>
</div>
@ -27,7 +27,7 @@
<span translate>Proposal Deleted</span>:
<b>{{notification.message}}</b>
<div class="wallet-activity-amount">
{{notification.amountStr}}:
<formatted-amount value={{notification.amountStr}}></formatted-amount>:
</div>
</div>
@ -35,7 +35,7 @@
<span translate>Proposal Rejected</span>:
<b>{{notification.message}}</b>
<div class="wallet-activity-amount">
{{notification.amountStr}}:
<formatted-amount value={{notification.amountStr}}></formatted-amount>:
</div>
</div>
@ -43,7 +43,7 @@
<span translate>New Proposal</span>:
<b>{{notification.message}}</b>
<div class="wallet-activity-amount">
{{notification.amountStr}}
<formatted-amount value={{notification.amountStr}}></formatted-amount>
</div>
</span>
@ -51,7 +51,7 @@
<span translate>Proposal Accepted</span>:
<b>{{notification.message}}</b>
<div class="wallet-activity-amount">
{{notification.amountStr}}
<formatted-amount value={{notification.amountStr}}></formatted-amount>
</div>
</span>

View file

@ -8,10 +8,10 @@
</span>
<span ng-if="wallet.isComplete()">
<span ng-if="selectedPriceDisplay == 'crypto' && !wallet.balanceHidden && !wallet.scanning">
<formatted-amount value="{{wallet.status.totalBalanceStr ? wallet.status.totalBalanceStr : ( wallet.cachedBalance ? wallet.cachedBalance + (wallet.cachedBalanceUpdatedOn ? ' &middot; ' + ( wallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '') : '' ) }}"></formatted-amount>
<formatted-amount value="{{wallet.status.totalBalanceStr ? wallet.status.totalBalanceStr : ( wallet.cachedBalance ? wallet.cachedBalance : '' ) }}"></formatted-amount> {{(!wallet.status.totalBalanceStr && wallet.cachedBalanceUpdatedOn ? ' &middot; ' + ( wallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '')}}
</span>
<span ng-if="selectedPriceDisplay == 'fiat' && !wallet.balanceHidden && !wallet.scanning">
<formatted-amount value="{{wallet.status.totalBalanceAlternative ? wallet.status.totalBalanceAlternative : ( wallet.cachedBalance ? wallet.cachedBalance + (wallet.cachedBalanceUpdatedOn ? ' &middot; ' + ( wallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '') : '' ) }}" currency="{{wallet.status.alternativeIsoCode}}"></formatted-amount>
<formatted-amount value="{{wallet.status.totalBalanceAlternative ? wallet.status.totalBalanceAlternative : (wallet.cachedBalance ? wallet.cachedBalance : '') }}" currency="{{wallet.status.alternativeIsoCode}}"></formatted-amount> {{( !wallet.status.totalBalanceAlternative && wallet.cachedBalance ? (wallet.cachedBalanceUpdatedOn ? ' &middot; ' + ( wallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '') : '' )}}
</span>
<span ng-if="wallet.scanning" translate> Scanning funds... </span>

View file

@ -11,8 +11,8 @@
<div class="header {{vm.origin.currency.toLowerCase()}}" ng-class="vm.thirdParty.id">
<div class="content">
<p>{{vm.sendingTitle}}</p>
<p class="large">{{vm.primaryAmount}} {{vm.primaryCurrency}}</p>
<p ng-show="vm.secondaryAmount">{{vm.secondaryAmount}} {{vm.secondaryCurrency}}</p>
<p class="large"><formatted-amount value="{{vm.primaryAmount}}" currency="{{vm.primaryCurrency}}"></formatted-amount></p>
<p ng-show="vm.secondaryAmount"><formatted-amount value="{{vm.secondaryAmount}}" currency="{{vm.secondaryCurrency}}"></formatted-amount></p>
</div>
</div>
@ -89,7 +89,7 @@
<div class="fee-fiat positive" ng-if="vm.feeLessThanACent">Fee: Less than 1 cent</div>
<div class="fee-fiat" ng-class="vm.feeIsHigh ? 'negative' : 'positive'" ng-if="!vm.feeLessThanACent">Fee: {{vm.feeFiat}} {{vm.feeCurrency}}</div>
<div class="fee-crypto" ng-if="vm.feeCrypto">
{{vm.feeCrypto}} {{vm.origin.currency}}
<formatted-amount value="{{vm.feeCrypto}}" currency="{{vm.origin.currency}}"></formatted-amount>
</div>
</div>
</div>

View file

@ -16,8 +16,15 @@
></div>
</i>
<h2>{{fromWallet.name}}</h2>
<wallet-balance
display-as-fiat="{{displayBalanceAsFiat}}"
wallet-status="{{fromWallet.status}}"
wallet-cached-balance="{{fromWallet.cachedBalance}}"
wallet-cached-balance-updated-on="{{fromWallet.cachedBalanceUpdatedOn}}"
wallet-cached-status="{{fromWallet.cachedStatus}}"
total-balance-sat="{{fromWallet.status.totalBalanceSat}}"></wallet-balance>
<!--<p ng-show="vm.origin.balanceAmount">{{vm.origin.balanceAmount}} {{vm.origin.balanceCurrency}}</p>-->
<formatted-amount value="{{fromWallet.status.totalBalanceStr ? fromWallet.status.totalBalanceStr : ( fromWallet.cachedBalance ? fromWallet.cachedBalance + (fromWallet.cachedBalanceUpdatedOn ? ' &middot; ' + ( fromWallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '') : '' ) }}"></formatted-amount>
<!--<formatted-amount value="{{fromWallet.status.totalBalanceStr ? fromWallet.status.totalBalanceStr : ( fromWallet.cachedBalance ? fromWallet.cachedBalance + (fromWallet.cachedBalanceUpdatedOn ? ' &middot; ' + ( fromWallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '') : '' ) }}"></formatted-amount>-->
</div>
</div>
</div>

View file

@ -10,6 +10,11 @@
</button>
</ion-nav-buttons>
</ion-nav-bar>
<style type="text/css">
.button-white-outline.button-outline.active, .button-white-outline.button-outline.activated {
color: {{ wallet.color }};
}
</style>
<div class="bp-content" ng-class="{'status-bar': isCordova}">
@ -41,7 +46,7 @@
class="size-14 amount-alternative"
ng-if="status.totalBalanceStr && wallet.network == 'livenet'"
ng-style="{opacity: altAmountOpacity}">
<formatted-amount value="{{status.totalBalanceStr}}"></formatted-amount>
<formatted-amount value="{{status.totalBalanceStr}}" size-equal="true"></formatted-amount>
</div>
</div>