Wallet/src/js/controllers/wallet-details.controller.js

493 lines
14 KiB
JavaScript
Raw Normal View History

2016-08-15 10:25:43 -03:00
'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, walletHistoryService) {
2018-08-21 08:58:19 +12:00
// 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 = [];
// For gradual migration for doing it properly
$scope.vm = {
allowInfiniteScroll: false,
gettingCachedHistory: true,
gettingInitialHistory: true,
updatingTxHistory: false,
fetchedAllTxHistory: false,
//updateTxHistoryError: false
updateTxHistoryFailed: false
};
2018-08-21 08:58:19 +12:00
// 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';
2018-08-21 08:58:19 +12:00
$scope.filteredTxHistory = [];
2016-10-10 15:19:33 -03:00
$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;
2018-08-21 08:58:19 +12:00
// 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;
2016-08-23 17:31:50 -03:00
2018-07-25 16:17:42 +09:00
var channel = "ga";
if (platformInfo.isCordova) {
channel = "firebase";
2018-07-13 17:19:31 +09:00
}
var log = new window.BitAnalytics.LogEvent("wallet_details_open", [], [channel]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
2016-09-05 14:59:11 -03:00
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
2016-08-23 17:31:50 -03:00
var setPendingTxps = function(txps) {
if (!txps) {
$scope.txps = [];
return;
}
$scope.txps = lodash.sortBy(txps, 'createdOn').reverse();
};
var analyzeUtxosDone;
var analyzeUtxos = function() {
if (analyzeUtxosDone) return;
2017-08-29 15:47:39 -03:00
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
2017-06-23 12:11:54 -03:00
if (err) return;
walletService.getLowUtxos($scope.wallet, levels, function(err, resp) {
2017-06-23 12:11:54 -03:00
if (err || !resp) return;
analyzeUtxosDone = true;
$scope.lowUtxosWarning = resp.warning;
});
});
};
var updateStatus = function(force) {
2016-08-23 17:31:50 -03:00
$scope.updatingStatus = true;
2016-11-14 12:53:43 -03:00
$scope.updateStatusError = null;
2016-09-08 12:13:37 -03:00
$scope.walletNotRegistered = false;
$scope.vm.fetchedAllTxHistory = false;
2016-08-23 17:31:50 -03:00
walletService.getStatus($scope.wallet, {
2016-08-23 17:31:50 -03:00
force: !!force,
}, function(err, status) {
$scope.updatingStatus = false;
if (err) {
2016-09-08 12:13:37 -03:00
if (err === 'WALLET_NOT_REGISTERED') {
$scope.walletNotRegistered = true;
} else {
2017-01-16 16:00:09 -03:00
$scope.updateStatusError = bwcError.msg(err, gettextCatalog.getString('Could not update wallet'));
2016-09-08 12:13:37 -03:00
}
2016-08-23 17:31:50 -03:00
$scope.status = null;
2016-11-14 12:53:43 -03:00
} else {
setPendingTxps(status.pendingTxps);
if (!$scope.status || status.balance.totalAmount != $scope.status.balance.totalAmount) {
$scope.status = status;
}
2016-08-23 17:31:50 -03:00
}
2016-08-24 17:54:01 -03:00
$timeout(function() {
2016-08-23 17:45:23 -03:00
$scope.$apply();
2016-11-14 12:53:43 -03:00
});
2016-08-24 17:54:01 -03:00
analyzeUtxos();
2016-08-23 17:31:50 -03:00
});
};
2016-08-15 10:25:43 -03:00
$scope.openSearchModal = function() {
$scope.color = $scope.wallet.color;
2017-05-30 16:19:06 -03:00
$scope.isSearching = true;
$scope.txHistorySearchResults = [];
$scope.filteredTxHistory = [];
2016-08-15 10:25:43 -03:00
$ionicModal.fromTemplateUrl('views/modals/search.html', {
scope: $scope,
focusFirstInput: true
}).then(function(modal) {
$scope.searchModal = modal;
$scope.searchModal.show();
});
2016-09-02 14:29:34 -03:00
$scope.close = function() {
2017-05-30 16:19:06 -03:00
$scope.isSearching = false;
2016-09-02 14:29:34 -03:00
$scope.searchModal.hide();
2016-10-21 19:13:14 -04:00
};
2016-11-04 17:15:18 -03:00
$scope.openTx = function(tx) {
$ionicHistory.nextViewOptions({
disableAnimate: true
});
2017-05-30 16:19:06 -03:00
$scope.close();
2016-11-04 17:15:18 -03:00
$scope.openTxModal(tx);
};
2016-08-15 10:25:43 -03:00
};
2016-08-18 17:56:04 -03:00
$scope.openTxModal = function(btx) {
2016-08-15 10:25:43 -03:00
$scope.btx = lodash.cloneDeep(btx);
$scope.walletId = $scope.wallet.id;
2016-10-22 17:43:05 -03:00
$state.transitionTo('tabs.wallet.tx-details', {
txid: $scope.btx.txid,
walletId: $scope.walletId
});
2016-08-15 10:25:43 -03:00
};
$scope.openBalanceModal = function() {
$ionicModal.fromTemplateUrl('views/modals/wallet-balance.html', {
scope: $scope
}).then(function(modal) {
$scope.walletBalanceModal = modal;
$scope.walletBalanceModal.show();
});
$scope.close = function() {
$scope.walletBalanceModal.hide();
};
};
2016-08-18 10:37:08 -03:00
$scope.recreate = function() {
walletService.recreate($scope.wallet, function(err) {
2016-09-08 12:13:37 -03:00
if (err) return;
$timeout(function() {
walletService.startScan($scope.wallet, function() {
2018-08-22 19:28:24 +12:00
$scope.updateAll(true, true);
2016-09-08 12:13:37 -03:00
$scope.$apply();
});
});
});
2016-08-18 10:37:08 -03:00
};
2016-08-17 18:48:30 -03:00
function applyCurrencyAliases(txHistory) {
var defaults = configService.getDefaults();
var configCache = configService.getSync();
lodash.each(txHistory, function onTx(tx) {
tx.amountUnitStr = $scope.wallet.coin == 'btc'
? (configCache.bitcoinAlias || defaults.bitcoinAlias)
: (configCache.bitcoinCashAlias || defaults.bitcoinCashAlias);
tx.amountUnitStr = tx.amountUnitStr.toUpperCase();
});
}
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() {
walletHistoryService.getCachedTxHistory($scope.wallet.id, function onGetCachedTxHistory(err, txHistory){
$scope.vm.gettingCachedHistory = false;
if (err) {
2018-08-21 08:58:19 +12:00
// 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);
2018-08-21 08:58:19 +12:00
completeTxHistory = txHistory;
showHistory(false);
$scope.$apply();
});
}
function fetchAndShowTxHistory(getLatest, flushCacheOnNew) {
$scope.vm.updatingTxHistory = true;
2018-08-21 08:58:19 +12:00
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);
2018-08-21 08:58:19 +12:00
completeTxHistory = txHistory;
showHistory(true);
$scope.$apply();
});
}
2018-08-21 08:58:19 +12:00
function showHistory(showAll) {
2018-08-21 08:58:19 +12:00
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;
2016-08-18 10:37:08 -03:00
}
2018-08-21 08:58:19 +12:00
}
$scope.getDate = function(txCreated) {
2016-11-02 17:01:32 -04:00
var date = new Date(txCreated * 1000);
return date;
2016-08-18 10:37:08 -03:00
};
2016-11-04 13:29:19 -04:00
$scope.isFirstInGroup = function(index) {
2016-11-15 11:03:45 -03:00
if (index === 0) {
return true;
}
var curTx = $scope.txHistory[index];
var prevTx = $scope.txHistory[index - 1];
2017-06-08 15:01:11 -04:00
return !$scope.createdDuringSameMonth(curTx, prevTx);
};
2016-11-04 13:29:19 -04:00
$scope.isLastInGroup = function(index) {
2016-11-15 11:03:45 -03:00
if (index === $scope.txHistory.length - 1) {
2016-11-04 13:29:19 -04:00
return true;
}
return $scope.isFirstInGroup(index + 1);
};
2017-06-07 18:55:43 -04:00
$scope.createdDuringSameMonth = function(curTx, prevTx) {
return timeService.withinSameMonth(curTx.time * 1000, prevTx.time * 1000);
2017-06-07 18:55:43 -04:00
};
2016-11-02 17:01:32 -04:00
2016-11-03 17:29:29 -04:00
$scope.createdWithinPastDay = function(time) {
2017-06-07 18:55:43 -04:00
return timeService.withinPastDay(time);
};
2016-11-02 17:01:32 -04:00
$scope.isDateInCurrentMonth = function(date) {
2017-06-07 18:55:43 -04:00
return timeService.isDateInCurrentMonth(date);
2016-11-02 17:01:32 -04:00
};
2016-11-03 17:29:29 -04:00
$scope.isUnconfirmed = function(tx) {
return !tx.confirmations || tx.confirmations === 0;
2016-11-03 17:29:29 -04:00
};
2018-08-21 08:58:19 +12:00
// on-infinite="showMore()"
2016-08-18 10:37:08 -03:00
$scope.showMore = function() {
2018-08-21 08:58:19 +12:00
// Check if we have more than we are displaying
if (completeTxHistory.length > $scope.txHistory.length) {
currentTxHistoryDisplayPage++;
2018-08-22 19:39:32 +12:00
showHistory(false);
2018-08-21 08:58:19 +12:00
$scope.$broadcast('scroll.infiniteScrollComplete');
return;
}
if ($scope.vm.updatingTxHistory) {
return;
}
fetchAndShowTxHistory(false, false);
2016-08-18 10:37:08 -03:00
};
2018-08-21 08:58:19 +12:00
// on-refresh="onRefresh()"
2016-10-10 15:19:33 -03:00
$scope.onRefresh = function() {
2016-10-14 10:25:52 -03:00
$timeout(function() {
$scope.$broadcast('scroll.refreshComplete');
}, 300);
2018-08-22 19:28:24 +12:00
$scope.updateAll(true, false);
2016-10-10 15:19:33 -03:00
};
2018-08-22 19:28:24 +12:00
$scope.updateAll = function(forceStatusUpdate, flushTxCacheOnNew)  {
updateStatus(forceStatusUpdate);
//updateTxHistory(cb);
2018-08-22 19:28:24 +12:00
fetchAndShowTxHistory(true, flushTxCacheOnNew);
};
2016-08-18 10:37:08 -03:00
2016-08-15 10:25:43 -03:00
$scope.hideToggle = function() {
profileService.toggleHideBalanceFlag($scope.wallet.credentials.walletId, function(err) {
if (err) $log.error(err);
});
};
var prevPos;
$scope.txHistoryPaddingBottom = 0;
2016-11-15 11:03:45 -03:00
function getScrollPosition() {
var scrollPosition = $ionicScrollDelegate.getScrollPosition();
$timeout(function() {
getScrollPosition();
}, 200);
if (!scrollPosition) {
return;
}
var pos = scrollPosition.top;
if (pos > 0) {
$scope.txHistoryPaddingBottom = "200px";
}
2016-11-15 11:03:45 -03:00
if (pos === prevPos) {
return;
}
prevPos = pos;
$scope.scrollPosition = pos;
}
2016-11-11 18:51:43 -05:00
var scrollWatcherInitialized;
$scope.$on("$ionicView.enter", function(event, data) {
2016-12-13 12:08:05 -03:00
if ($scope.isCordova && $scope.isAndroid) setAndroidStatusBarColor();
2016-11-11 18:51:43 -05:00
scrollWatcherInitialized = true;
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
configService.whenAvailable(function (config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
$timeout(function () {
2018-04-26 10:28:08 +09:00
$scope.$apply();
});
});
$scope.walletId = data.stateParams.walletId;
$scope.wallet = profileService.getWallet($scope.walletId);
if (!$scope.wallet) return;
$scope.requiresMultipleSignatures = $scope.wallet.credentials.m > 1;
$scope.vm.gettingInitialHistory = true;
2017-08-30 14:52:30 -03:00
addressbookService.list(function(err, ab) {
if (err) $log.error(err);
$scope.addressbook = ab || {};
});
listeners = [
$rootScope.$on('bwsEvent', function(e, walletId) {
2017-02-01 15:41:20 -03:00
if (walletId == $scope.wallet.id && e.type != 'NewAddress')
2018-08-22 19:28:24 +12:00
$scope.updateAll(false, false);
}),
$rootScope.$on('Local/TxAction', function(e, walletId) {
if (walletId == $scope.wallet.id)
2018-08-22 19:28:24 +12:00
$scope.updateAll(false, false);
}),
];
});
2017-12-18 12:07:41 +00:00
var refreshInterval;
2017-02-02 18:04:08 -03:00
$scope.$on("$ionicView.afterEnter", function(event, data) {
$scope.updateAll();
// refreshAmountSection();
refreshInterval = $interval($scope.onRefresh, 10 * 1000);
$timeout(function() {
getScrollPosition();
}, 1000);
2017-02-02 18:04:08 -03:00
});
$scope.$on("$ionicView.afterLeave", function(event, data) {
2017-12-18 12:07:41 +00:00
$interval.cancel(refreshInterval);
2016-12-12 17:29:11 -03:00
if ($window.StatusBar) {
$window.StatusBar.backgroundColorByHexString('#000000');
}
});
$scope.$on("$ionicView.leave", function(event, data) {
lodash.each(listeners, function(x) {
x();
});
});
function setAndroidStatusBarColor() {
var SUBTRACT_AMOUNT = 15;
var walletColor;
if (!$scope.wallet.color) walletColor = appConfigService.name == 'copay' ? '#019477' : '#4a90e2';
else walletColor = $scope.wallet.color;
var rgb = hexToRgb(walletColor);
var keys = Object.keys(rgb);
keys.forEach(function(k) {
2016-12-12 17:29:11 -03:00
if (rgb[k] - SUBTRACT_AMOUNT < 0) {
rgb[k] = 0;
} else {
rgb[k] -= SUBTRACT_AMOUNT;
}
});
var statusBarColorHexString = rgbToHex(rgb.r, rgb.g, rgb.b);
2016-12-13 12:08:05 -03:00
if ($window.StatusBar)
$window.StatusBar.backgroundColorByHexString(statusBarColorHexString);
}
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function rgbToHex(r, g, b) {
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
$scope.goToSend = function() {
2018-08-30 16:03:51 +09:00
sendFlowService.start({
fromWalletId: $scope.wallet.id
});
};
$scope.goToReceive = function() {
$state.go('tabs.home', {
walletId: $scope.wallet.id
}).then(function () {
$ionicHistory.clearHistory();
$state.go('tabs.receive', {
walletId: $scope.wallet.id
});
});
};
$scope.goToBuy = function() {
$state.go('tabs.home', {
walletId: $scope.wallet.id
}).then(function () {
$ionicHistory.clearHistory();
$state.go('tabs.buyandsell');
});
};
2016-08-15 10:25:43 -03:00
});