diff --git a/public/views/walletHome.html b/public/views/walletHome.html index faf16d9ef..7e98c2f5b 100644 --- a/public/views/walletHome.html +++ b/public/views/walletHome.html @@ -455,6 +455,24 @@ +
+
+
+
+
+
+
+
+
+
+
+
+ + + + Download CSV file + +
-
-
- -
-
-
-
-
-
-
-
-
- -
- - - - Download CSV file -
diff --git a/src/js/controllers/index.js b/src/js/controllers/index.js index 988228bd5..b37adad0e 100644 --- a/src/js/controllers/index.js +++ b/src/js/controllers/index.js @@ -2,11 +2,12 @@ angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, lodash, go, profileService, configService, isCordova, rateService, storageService, addressService, gettext, gettextCatalog, amMoment, nodeWebkit, addonManager, feeService, isChromeApp, bwsError, txFormatService, uxLanguage, $state, glideraService, isMobile) { var self = this; + var SOFT_CONFIRMATION_LIMIT = 12; self.isCordova = isCordova; self.isChromeApp = isChromeApp; self.isSafari = isMobile.Safari(); self.onGoingProcess = {}; - self.limitHistory = 5; + self.limitHistory = 6; function strip(number) { return (parseFloat(number.toPrecision(12))); @@ -84,7 +85,6 @@ angular.module('copayApp.controllers').controller('indexController', function($r self.txHistory = []; self.txHistoryUnique = {}; self.balanceByAddress = null; - self.txHistoryPaging = false; self.pendingTxProposalsCountForUs = null; self.setSpendUnconfirmed(); @@ -404,48 +404,6 @@ angular.module('copayApp.controllers').controller('indexController', function($r }); }; - self.updateTxHistory = function(skip) { - var fc = profileService.focusedClient; - if (!fc || !fc.isComplete()) return; - if (!skip) { - self.txHistory = []; - self.txHistoryUnique = {}; - } - self.skipHistory = skip || 0; - $log.debug('Updating Transaction History'); - self.txHistoryError = false; - self.updatingTxHistory = true; - self.txHistoryPaging = false; - - $timeout(function() { - fc.getTxHistory({ - skip: self.skipHistory, - limit: self.limitHistory + 1 - }, function(err, txs) { - self.updatingTxHistory = false; - if (err) { - $log.debug('TxHistory ERROR:', err); - // We do not should errors here, since history is usually - // fetched AFTER others requests (if skip=0) - if (skip) - self.handleError(err); - - self.txHistoryError = true; - } else { - $log.debug('Wallet Transaction History:', txs); - self.skipHistory = self.skipHistory + self.limitHistory; - self.setTxHistory(txs); - } - $rootScope.$apply(); - }); - }); - }; - - self.debouncedUpdateHistory = lodash.throttle(function() { - self.updateTxHistory(); - }, 5000); - - // This handles errors from BWS/index with are nomally // trigger from async events (like updates) self.handleError = function(err) { @@ -528,8 +486,8 @@ angular.module('copayApp.controllers').controller('indexController', function($r self.setTxHistory = function(txs) { var config = configService.getSync().wallet.settings; var now = Math.floor(Date.now() / 1000); - var c = 0; - self.txHistoryPaging = txs[self.limitHistory] ? true : false; + self.txHistoryUnique = {}; + self.hasUnsafeConfirmed = false; lodash.each(txs, function(tx) { tx = txFormatService.processTx(tx); @@ -545,14 +503,11 @@ angular.module('copayApp.controllers').controller('indexController', function($r self.hasUnsafeConfirmed = true; } - if (c < self.limitHistory) { - if (!self.txHistoryUnique[tx.txid]) { - self.txHistory.push(tx); - self.txHistoryUnique[tx.txid] = true; - c++; - } else { - $log.debug('Ignoring duplicate TX in history: '+ tx.txid) - } + if (!self.txHistoryUnique[tx.txid]) { + self.txHistory.push(tx); + self.txHistoryUnique[tx.txid] = true; + } else { + $log.debug('Ignoring duplicate TX in history: ' + tx.txid) } }); }; @@ -691,45 +646,40 @@ angular.module('copayApp.controllers').controller('indexController', function($r } var step = 6; - var unique = {}; - function getHistory(skip, cb) { - skip = skip || 0; - fc.getTxHistory({ - skip: skip, - limit: step, - }, function(err, txs) { + + function getHistory(cb) { + storageService.getTxHistory(c.walletId, function(err, txs) { if (err) return cb(err); - if (txs && txs.length > 0) { - lodash.each(txs, function(tx) { - if (!unique[tx.txid]){ - allTxs.push(tx); - unique[tx.txid] = 1; - console.log("Got:" + lodash.keys(unique).length + " txs"); - } else { - console.log("Ignoring duplicate TX in CSV: "+ tx.txid); - } - }); - return getHistory(skip + step, cb); - } else { - return cb(null, lodash.flatten(allTxs)); + + var txsFromLocal = []; + try { + txsFromLocal = JSON.parse(txs); + } catch (ex) { + $log.warn(ex); } + + allTxs.push(txsFromLocal); + return cb(null, lodash.flatten(allTxs)); }); - }; + } if (isCordova) { - $log.info('Not available on mobile'); + $log.info('CSV generation not available in mobile'); return; } var isNode = nodeWebkit.isDefined(); var fc = profileService.focusedClient; + var c = fc.credentials; if (!fc.isComplete()) return; var self = this; var allTxs = []; + $log.debug('Generating CSV from History'); self.setOngoingProcess('generatingCSV', true); + $timeout(function() { - getHistory(null, function(err, txs) { + getHistory(function(err, txs) { self.setOngoingProcess('generatingCSV', false); if (err) { self.handleError(err); @@ -741,6 +691,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r var satToBtc = 1 / 100000000; var filename = 'Copay-' + (self.alias || self.walletName) + '.csv'; var csvContent = ''; + if (!isNode) csvContent = 'data:text/csv;charset=utf-8,'; csvContent += 'Date,Destination,Note,Amount,Currency,Spot Value,Total Value,Tax Type,Category\n'; @@ -782,6 +733,116 @@ angular.module('copayApp.controllers').controller('indexController', function($r }); }; + self.stopSync = function(remoteTx, localTx) { + if (remoteTx.txid == localTx.txid) + return true; + else + return false; + } + + self.removeSoftConfirmedTx = function(txs) { + return lodash.map(txs, function(tx) { + if (tx.confirmations >= SOFT_CONFIRMATION_LIMIT) + return tx; + }); + } + + self.getConfirmedTxs = function(cb) { + var fc = profileService.focusedClient; + var c = fc.credentials; + + storageService.getTxHistory(c.walletId, function(err, txs) { + if (err) return cb(err); + + var localTxs = []; + try { + localTxs = JSON.parse(txs); + } catch (ex) { + $log.warn(ex); + } + + return cb(null, self.removeSoftConfirmedTx(localTxs)); + }); + } + + self.updateLocalTxHistory = function(cb) { + self.getConfirmedTxs(function(err, txsFromLocal) { + if (err) return cb(err); + + var fc = profileService.focusedClient; + var c = fc.credentials; + fillTxsObject(); + + function fillTxsObject(txsResult, index) { + txsResult = txsResult || []; + index = index || 0; + + self.makeTxHistoryRequest(txsResult, index, txsFromLocal[0], function(err, newIndex, exitLoop) { + if (err) return cb(err); + if (exitLoop) { + self.txHistory = []; + self.setTxHistory(lodash.compact(txsResult.concat(txsFromLocal))); + return storageService.setTxHistory(JSON.stringify(self.txHistory), c.walletId, function() { + return cb(null); + }); + } + fillTxsObject(txsResult, newIndex); + }); + }; + }); + } + + self.makeTxHistoryRequest = function(txsResult, index, endingTx, cb) { + var fc = profileService.focusedClient; + var c = fc.credentials; + var exitLoop = false; + + fc.getTxHistory({ + skip: index, + limit: self.limitHistory + 1 + }, function(err, txsFromBWC) { + if (err) return cb(err); + + if (!txsFromBWC[0]) + exitLoop = true; + + lodash.each(txsFromBWC, function(t) { + if (!endingTx) txsResult.push(t); + else { + if (!self.stopSync(t, endingTx) && !exitLoop) { + txsResult.push(t); + } else { + exitLoop = true; + } + } + }); + index = index + self.limitHistory; + return cb(null, index, exitLoop); + }); + } + + self.updateHistory = function() { + $log.debug('Updating Transaction History'); + self.txHistoryError = false; + self.updatingTxHistory = true; + + $timeout(function() { + self.updateLocalTxHistory(function(err) { + if (err) self.txHistoryError = true; + self.updatingTxHistory = false; + $rootScope.$apply(); + }); + }); + }; + + self.updateTxHistory = lodash.debounce(function() { + self.updateHistory(); + }, 1000); + + self.throttledUpdateHistory = lodash.throttle(function() { + self.updateHistory(); + }, 5000); + self.showErrorPopup = function(msg, cb) { $log.warn('Showing err popup:' + msg); self.showAlert = { @@ -1090,7 +1151,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r } else if (self.hasUnsafeConfirmed) { $log.debug('Wallet has transactions with few confirmations. Updating.') if (self.network == 'testnet') { - self.debouncedUpdateHistory(); + self.throttledUpdateHistory(); } else { self.updateTxHistory(); } diff --git a/src/js/controllers/preferencesDelete.js b/src/js/controllers/preferencesDelete.js index 7fbc0c4d2..7d30f4685 100644 --- a/src/js/controllers/preferencesDelete.js +++ b/src/js/controllers/preferencesDelete.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('preferencesDeleteWalletController', - function($scope, $rootScope, $filter, $timeout, $modal, $log, notification, profileService, isCordova, go, gettext, gettextCatalog, animationService) { + function($scope, $rootScope, $filter, $timeout, $modal, $log, storageService, notification, profileService, isCordova, go, gettext, gettextCatalog, animationService) { this.isCordova = isCordova; this.error = null; @@ -46,14 +46,19 @@ angular.module('copayApp.controllers').controller('preferencesDeleteWalletContro var _deleteWallet = function() { var fc = profileService.focusedClient; var name = fc.credentials.walletName; - var walletName = (fc.alias||'') + ' [' + name + ']'; + var walletName = (fc.alias || '') + ' [' + name + ']'; var self = this; profileService.deleteWalletFC({}, function(err) { if (err) { self.error = err.message || err; } else { - notification.success(gettextCatalog.getString('Success'), gettextCatalog.getString('The wallet "{{walletName}}" was deleted', {walletName: walletName})); + storageService.removeTxHistory(fc.credentials.walletId, function() { + notification.success(gettextCatalog.getString('Success'), gettextCatalog.getString('The wallet "{{walletName}}" was deleted', { + walletName: walletName + })); + return; + }); } }); }; diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index b19db8779..9673863ff 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -216,5 +216,17 @@ angular.module('copayApp.services') storage.remove('addressbook-' + network, cb); }; + root.setTxHistory = function(txs, walletId, cb) { + storage.set('txsHistory-' + walletId, txs, cb); + } + + root.getTxHistory = function(walletId, cb) { + storage.get('txsHistory-' + walletId, cb); + } + + root.removeTxHistory = function(walletId, cb) { + storage.remove('txsHistory-' + walletId, cb); + } + return root; });