Merged sprint 21.

This commit is contained in:
Brendon Duncan 2018-09-21 17:16:18 -07:00
commit 4d623d51d7
11 changed files with 1121 additions and 1039 deletions

View file

@ -366,13 +366,13 @@ module.exports = function(grunt) {
grunt.registerTask('build-mobile-release', ['build-ios-release', 'build-android-release']);
// Build ios
grunt.registerTask('start-ios', ['exec:build_ios_debug', 'exec:xcode']);
grunt.registerTask('build-ios-debug', ['exec:build_ios_debug']);
grunt.registerTask('start-ios', ['default', 'exec:build_ios_debug', 'exec:xcode']);
grunt.registerTask('build-ios-debug', ['default', 'exec:build_ios_debug']);
grunt.registerTask('build-ios-release', ['prod', 'exec:build_ios_release']);
// Build android
grunt.registerTask('start-android', ['build-android-debug', 'exec:run_android']);
grunt.registerTask('build-android-debug', ['exec:build_android_debug']);
grunt.registerTask('build-android-debug', ['default', 'exec:build_android_debug']);
grunt.registerTask('start-android-emulator', ['build-android-debug', 'exec:run_android_emulator']);
grunt.registerTask('build-android-release', ['prod', 'exec:build_android_release', 'sign-android']);
grunt.registerTask('sign-android', ['exec:sign_android']);

View file

@ -1,10 +1,12 @@
'use strict';
(function () {
angular
.module('copayApp.controllers')
.controller('reviewController', reviewController);
function reviewController(addressbookService, bitcoinCashJsService, bitcore, bitcoreCash, bwcError, clipboardService, configService, feeService, gettextCatalog, $interval, $ionicHistory, $ionicModal, ionicToast, lodash, $log, ongoingProcess, platformInfo, popupService, profileService, $scope, sendFlowService, shapeshiftService, soundService, $state, $timeout, txConfirmNotification, txFormatService, walletService) {
function reviewController(addressbookService, bitcoinCashJsService, bitcore, bitcoreCash, bwcError, clipboardService, configService, feeService, gettextCatalog, $interval, $ionicHistory, $ionicModal, ionicToast, lodash, $log, ongoingProcess, platformInfo, popupService, profileService, $scope, sendFlowService, shapeshiftService, soundService, $state, $timeout, txConfirmNotification, txFormatService, walletService) {
var vm = this;
vm.buttonText = '';
@ -26,6 +28,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
vm.feeIsHigh = false;
vm.feeLessThanACent = false;
vm.isCordova = platformInfo.isCordova;
vm.memo = '';
vm.notReadyMessage = '';
vm.origin = {
balanceAmount: '',
@ -79,6 +82,9 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
function onBeforeEnter(event, data) {
console.log('review onBeforeEnter sendflow ', sendFlowService.state);
// Reset from last time
vm.memo = '';
defaults = configService.getDefaults();
sendFlowData = sendFlowService.state.getClone();
originWalletId = sendFlowData.fromWalletId;
@ -392,12 +398,12 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
var balanceCryptoAmount = '';
var balanceCryptoCurrencyCode = '';
var balanceFiatAmount = '';
var balanceFiatCurrency = ''
var balanceFiatCurrency = '';
var displayAmount = '';
var displayCurrency = '';
var walletStatus = null;
if (wallet.status.isValid) {
if (wallet.status && wallet.status.isValid) {
walletStatus = wallet.status;
} else if (wallet.cachedStatus.isValid) {
walletStatus = wallet.cachedStatus;
@ -948,5 +954,5 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
});
});
}
}
}
})();

View file

@ -10,7 +10,7 @@ angular.module('copayApp.controllers').controller('shapeshiftController', functi
walletsBtc = profileService.getWallets({coin: 'btc'});
walletsBch = profileService.getWallets({coin: 'bch'});
$scope.fromWallets = lodash.filter(walletsBtc.concat(walletsBch), function(w) {
return w.status.balance.availableAmount > 0;
return (w.status && w.status.balance && w.status.balance.availableAmount > 0);
});
$scope.singleFromWallet = $scope.fromWallets.length === 1;

View file

@ -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') {
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'];
} else {
$scope.addr = addr;
// listen to btc address
currentAddressSocket = new WebSocket("wss://ws.blockchain.info/inv");
paymentSubscriptionObj.addr = $scope.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;
});
});

View file

@ -203,6 +203,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
function updateTxHistoryFromCachedData() {
$scope.vm.gettingCachedHistory = true;
walletHistoryService.getCachedTxHistory($scope.wallet.id, function onGetCachedTxHistory(err, txHistory){
$scope.vm.gettingCachedHistory = false;
if (err) {
@ -400,8 +401,9 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
var refreshInterval;
$scope.$on("$ionicView.afterEnter", function(event, data) {
$scope.updateAll();
$scope.$on("$ionicView.afterEnter", function onAfterEnter(event, data) {
updateTxHistoryFromCachedData();
$scope.updateAll(true, true);
// refreshAmountSection();
refreshInterval = $interval($scope.onRefresh, 10 * 1000);
$timeout(function() {

View file

@ -1,7 +1,12 @@
'use strict';
angular.module('copayApp.controllers').controller('walletSelectorController', function($scope, $state, sendFlowService, configService, gettextCatalog, profileService, txFormatService) {
(function () {
angular
.module('copayApp.controllers')
.controller('walletSelectorController', walletSelectorController);
function walletSelectorController ($scope, $state, sendFlowService, configService, gettextCatalog, ongoingProcess, profileService, walletService, txFormatService) {
var fromWalletId = '';
var priceDisplayAsFiat = false;
var unitDecimals = 0;
@ -116,32 +121,41 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
if ($scope.type === 'origin') {
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send from');
if ($scope.params.amount) {
if ($scope.params.amount || $scope.coin) {
walletsAll = profileService.getWallets({coin: $scope.coin});
walletsAll.forEach(function forWallet(wallet){
if (wallet.status.availableBalanceSat > $scope.params.amount) {
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') {
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;
}
} else if ($scope.coin) {
walletsAll = profileService.getWallets({coin: $scope.coin});
walletsAll.forEach(function forWallet(wallet){
if (wallet.status.availableBalanceSat > 0) {
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') {
@ -186,4 +200,5 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
sendFlowService.router.goBack();
}
});
}
})();

View file

@ -12,6 +12,7 @@
totalBalanceSat: '@',
// The Wallet object is sometimes not stringify()-able, so not interpolatable,
// so can't be passed to a directive.
walletCoin: '@',
walletStatus: '@',
walletCachedBalance: '@',
walletCachedBalanceUpdatedOn: '@',
@ -31,7 +32,6 @@
});
function displayCryptoBalance(walletStatus, walletCachedBalance, walletCachedBalanceUpdatedOn, walletCachedStatus) {
console.log('displayCryptoBalance()');
if (walletStatus && walletStatus.isValid && walletStatus.totalBalanceStr) {
setDisplay(walletStatus.totalBalanceStr, '');
@ -52,7 +52,7 @@
setDisplay('', '');
}
function displayFiatBalance(walletStatus, walletCachedStatus) {
function displayFiatBalance(walletStatus, walletCachedStatus, walletCoin) {
var displayAmount = '';
if (walletStatus && walletStatus.isValid && walletStatus.alternativeBalanceAvailable) {
displayAmount = walletStatus.totalBalanceAlternative + ' ' + walletStatus.alternativeIsoCode;
@ -66,7 +66,7 @@
return;
}
getFiatBalance(wallet);
getFiatBalance(walletStatus, walletCachedStatus, walletCoin);
}
function formatBalance() {
@ -94,19 +94,30 @@
}
if (displayAsFiat) {
displayFiatBalance(walletStatusObj, walletCachedStatusObj);
displayFiatBalance(walletStatusObj, walletCachedStatusObj, $scope.walletCoin);
}
}
function getFiatBalance(wallet) {
if (!(wallet.status && wallet.status.isValid)) {
$log.warn('Abandoning call to get fiat balance, because no valid wallet status.');
function getFiatBalance(walletStatus, walletCachedStatus, walletCoin) {
var totalBalanceSat = null;
if (walletStatus && walletStatus.isValid) {
totalBalanceSat = walletStatus.totalBalanceSat
} else if (walletCachedStatus && walletCachedStatus.isValid) {
totalBalanceSat = walletCachedStatus.totalBalanceSat
}
// 0 is valid
if (totalBalanceSat === null) {
$log.warn('Abandoning call to get fiat balance, because no valid wallet status (cached or otherwise).');
return;
}
txFormatService.formatAlternativeStr(wallet.coin, wallet.status.totalBalanceSat, function onFormatAlernativeStr(formatted) {
txFormatService.formatAlternativeStr(walletCoin, totalBalanceSat, function onFormatAlernativeStr(formatted) {
if (formatted) {
setDisplay(formatted, '');
} else {
$log.error('Failed to format fiat balance of wallet.');
}
});
}

View file

@ -75,9 +75,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
var showName = $filter('translate')(processNames[name] || name);
if (customHandler) {
customHandler(processName, showName, isOn);
} else if (root.onGoingProcessName) {
if (root.onGoingProcessName) {
var tmpl;
if (isWindowsPhoneApp) tmpl = '<div>' + showName + '</div>';
else tmpl = '<div class="item-icon-left">' + showName + '<ion-spinner class="spinner-stable" icon="lines"></ion-spinner></div>';
@ -87,6 +85,10 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
} else {
$ionicLoading.hide();
}
if (customHandler) {
customHandler(processName, showName, isOn);
}
};
return root;

View file

@ -27,20 +27,23 @@
function addEarlyTransactions(walletId, cachedTxs, newTxs) {
var cachedTxIds = {};
var cachedTxIndexFromId = {};
cachedTxs.forEach(function forCachedTx(tx){
cachedTxIds[tx.txid] = true;
cachedTxIndexFromId[tx.txid] = true;
});
var confirmationsUpdated = false;
var someTransactionsWereNew = false;
var overlappingTxsCount = 0;
newTxs.forEach(function forNewTx(tx){
if (cachedTxIds[tx.txid]) {
overlappingTxsCount++;
} else {
if (typeof cachedTxIndexFromId[tx.txid] === "undefined") {
someTransactionsWereNew = true;
cachedTxs.push(tx);
} else {
var txUpdated = updateCachedTx(cachedTxs, cachedTxIndexFromId, tx);
confirmationsUpdated = confirmationsUpdated || txUpdated;
overlappingTxsCount++;
}
});
@ -50,6 +53,8 @@
if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION) { // We are good
if (someTransactionsWereNew) {
saveTxHistory(walletId, cachedTxs);
} else if (confirmationsUpdated) {
saveTxHistory(walletId, cachedTxs);
} else if (overlappingTxsCount === newTxs.length) {
allTransactionsFetched = true;
}
@ -65,21 +70,24 @@
}
function addLatestTransactions(walletId, cachedTxs, newTxs) {
var cachedTxIds = {};
cachedTxs.forEach(function forCachedTx(tx){
cachedTxIds[tx.txid] = true;
var cachedTxIndexFromId = {};
cachedTxs.forEach(function forCachedTx(tx, txIndex){
cachedTxIndexFromId[tx.txid] = txIndex;
});
var someTransactionsWereNew = false;
var confirmationsUpdated = false;
var overlappingTxsCount = 0;
var uniqueNewTxs = [];
newTxs.forEach(function forNewTx(tx){
if (cachedTxIds[tx.txid]) {
overlappingTxsCount++;
} else {
if (typeof cachedTxIndexFromId[tx.txid] === "undefined") {
someTransactionsWereNew = true;
uniqueNewTxs.push(tx);
} else {
var txUpdated = updateCachedTx(cachedTxs, cachedTxIndexFromId, tx);
confirmationsUpdated = confirmationsUpdated || txUpdated;
overlappingTxsCount++;
}
});
@ -91,6 +99,9 @@
saveTxHistory(walletId, allTxs);
return allTxs;
} else {
if (confirmationsUpdated) {
saveTxHistory(walletId, cachedTxs);
}
return cachedTxs;
}
} else {
@ -104,6 +115,8 @@
// Only clear the cache once we have received new transactions from the server.
/**
* @param wallet
* @param start
* @param {function(err, txs)} cb - transactions is always an array, may be empty
*/
function fetchTxHistoryByPage(wallet, start, cb) {
@ -134,6 +147,7 @@
* @param {function(error, txs)} cb - txs is always an array, may be empty
*/
function getCachedTxHistory(walletId, cb) {
console.log('txhistory updateLocalTxHistoryByPage()');
storageService.getTxHistory(walletId, function onGetTxHistory(err, txHistoryString){
if (err) {
return cb(err, []);
@ -187,7 +201,7 @@
});
return processedTxs;
};
}
function saveTxHistory(walletId, processedTxs) {
storageService.setTxHistory(processedTxs, walletId, function onSetTxHistory(error){
@ -197,9 +211,26 @@
});
}
/**
* Returns true if the cached tx was updated
* @param {*} cachedTxs
* @param {*} cachedTxIndexFromId - Indices for cachedTxs, based on txid
* @param {*} tx - The most recent tx info
*/
function updateCachedTx(cachedTxs, cachedTxIndexFromId, tx) {
var updated = false;
var txIndex = cachedTxIndexFromId[tx.txid];
var cachedTx = cachedTxs[txIndex];
if (cachedTx.confirmations < SAFE_CONFIRMATIONS && tx.confirmations > cachedTx.confirmations) {
cachedTxs[txIndex].confirmations = tx.confirmations;
updated = true;
}
return updated;
}
function updateLocalTxHistoryByPage(wallet, getLatest, flushCacheOnNew, cb) {
console.log('txhistory updaetLocalTxHistoryByPage()');
if (flushCacheOnNew) {
fetchTxHistoryByPage(wallet, 0, function onFetchTxHistory(err, txs){
if (err) {
@ -240,10 +271,5 @@
});
}
}
}
})();

View file

@ -18,13 +18,12 @@
<h2>{{fromWallet.name}}</h2>
<wallet-balance
display-as-fiat="{{displayBalanceAsFiat}}"
wallet-coin="{{fromWallet.coin}}"
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>-->
</div>
</div>
</div>

View file

@ -13,7 +13,7 @@
<div class="header--request__amount-alt" ng-show="requestAmountSecondary" translate>{{requestAmountSecondary}} {{requestCurrencySecondary}}</div>
</div>
<div class="wallets-header">
<div class="title">
<div class="title" ng-if="walletsBch.length > 0 || walletsBtc.length > 0 || walletsInsufficientFunds.length > 0">
{{headerTitle}}
</div>
</div>