2015-03-06 12:00:10 -03:00
|
|
|
'use strict';
|
|
|
|
|
|
Addon support
Addons are simple Angular modules with views, controllers, services etc. Addons can register
themselves in Copay using pluginManagerProvider. It allows them to add extra items to the bottom
menu and as well as extra tab-views:
````
addonManagerProvider.registerAddon({
menuItem: {
'title': 'Assets',
'icon': 'icon-pricetag',
'link': 'assets'
},
view: {
id: 'assets',
'class': 'assets',
template: 'colored-coins/views/assets.html'
}
});
````
Addons can consume core Copay services and listen for events to react on changes. For this very
first addon system inplementation Copay emits additional BalanceUpdated event so that interested
addons can react on new transactions (see plugin reference implementation below).
As bottom menu can accomodate only 6 items without sacrificing usability, so it was reworked to
have second layer of items. Now If menu has more than 6 items, toggle button will be added to
the menu allowing to reveal extra items in a sliding panel. Bottom menu in this case will show
only 5 items, the rest will be rendered on sliding panel.
This changes addresses issue #2949 and reference implementation of addon could be found here:
https://github.com/troggy/copay-colored-coins-plugin
2015-07-04 13:02:46 +03:00
|
|
|
angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, lodash, go, profileService, configService, isCordova, rateService, storageService, addressService, gettextCatalog, gettext, amMoment, nodeWebkit, addonManager) {
|
2015-03-06 12:00:10 -03:00
|
|
|
var self = this;
|
|
|
|
|
self.isCordova = isCordova;
|
|
|
|
|
self.onGoingProcess = {};
|
2015-04-23 15:19:30 -03:00
|
|
|
self.limitHistory = 5;
|
2015-03-06 12:00:10 -03:00
|
|
|
|
|
|
|
|
function strip(number) {
|
|
|
|
|
return (parseFloat(number.toPrecision(12)));
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-07 18:35:54 -03:00
|
|
|
|
|
|
|
|
self.goHome = function() {
|
|
|
|
|
go.walletHome();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-04-22 02:48:00 -03:00
|
|
|
self.menu = [{
|
2015-04-29 19:19:10 -03:00
|
|
|
'title': gettext('Home'),
|
2015-04-22 02:48:00 -03:00
|
|
|
'icon': 'icon-home',
|
2015-04-23 17:45:32 -03:00
|
|
|
'link': 'walletHome'
|
2015-04-22 02:48:00 -03:00
|
|
|
}, {
|
2015-04-29 19:19:10 -03:00
|
|
|
'title': gettext('Receive'),
|
2015-04-29 12:16:28 -03:00
|
|
|
'icon': 'icon-receive2',
|
2015-04-22 02:48:00 -03:00
|
|
|
'link': 'receive'
|
|
|
|
|
}, {
|
2015-04-29 19:19:10 -03:00
|
|
|
'title': gettext('Send'),
|
2015-04-22 02:48:00 -03:00
|
|
|
'icon': 'icon-paperplane',
|
|
|
|
|
'link': 'send'
|
|
|
|
|
}, {
|
2015-04-29 19:19:10 -03:00
|
|
|
'title': gettext('History'),
|
2015-04-22 02:48:00 -03:00
|
|
|
'icon': 'icon-history',
|
|
|
|
|
'link': 'history'
|
2015-04-23 15:19:30 -03:00
|
|
|
}];
|
2015-04-22 02:48:00 -03:00
|
|
|
|
Addon support
Addons are simple Angular modules with views, controllers, services etc. Addons can register
themselves in Copay using pluginManagerProvider. It allows them to add extra items to the bottom
menu and as well as extra tab-views:
````
addonManagerProvider.registerAddon({
menuItem: {
'title': 'Assets',
'icon': 'icon-pricetag',
'link': 'assets'
},
view: {
id: 'assets',
'class': 'assets',
template: 'colored-coins/views/assets.html'
}
});
````
Addons can consume core Copay services and listen for events to react on changes. For this very
first addon system inplementation Copay emits additional BalanceUpdated event so that interested
addons can react on new transactions (see plugin reference implementation below).
As bottom menu can accomodate only 6 items without sacrificing usability, so it was reworked to
have second layer of items. Now If menu has more than 6 items, toggle button will be added to
the menu allowing to reveal extra items in a sliding panel. Bottom menu in this case will show
only 5 items, the rest will be rendered on sliding panel.
This changes addresses issue #2949 and reference implementation of addon could be found here:
https://github.com/troggy/copay-colored-coins-plugin
2015-07-04 13:02:46 +03:00
|
|
|
self.addonViews = addonManager.addonViews();
|
|
|
|
|
self.menu = self.menu.concat(addonManager.addonMenuItems());
|
|
|
|
|
self.menuItemSize = self.menu.length > 4 ? 2 : 3;
|
|
|
|
|
|
2015-04-23 12:27:43 -03:00
|
|
|
self.tab = 'walletHome';
|
|
|
|
|
|
2015-04-22 15:19:08 -03:00
|
|
|
self.availableLanguages = [{
|
2015-06-11 21:38:48 +02:00
|
|
|
name: gettext('Deutsch'),
|
2015-06-11 22:08:32 +02:00
|
|
|
isoCode: 'de',
|
2015-06-11 21:38:48 +02:00
|
|
|
}, {
|
2015-04-29 19:19:10 -03:00
|
|
|
name: gettext('English'),
|
2015-04-22 15:19:08 -03:00
|
|
|
isoCode: 'en',
|
|
|
|
|
}, {
|
2015-04-29 19:19:10 -03:00
|
|
|
name: gettext('Spanish'),
|
2015-04-22 15:19:08 -03:00
|
|
|
isoCode: 'es',
|
|
|
|
|
}, {
|
2015-04-29 19:19:10 -03:00
|
|
|
name: gettext('French'),
|
2015-04-22 15:19:08 -03:00
|
|
|
isoCode: 'fr',
|
|
|
|
|
}, {
|
2015-04-29 19:19:10 -03:00
|
|
|
name: gettext('Japanese'),
|
2015-04-22 15:19:08 -03:00
|
|
|
isoCode: 'ja',
|
2015-06-04 12:54:36 -03:00
|
|
|
}, {
|
|
|
|
|
name: gettext('Portuguese'),
|
|
|
|
|
isoCode: 'pt',
|
2015-04-22 15:19:08 -03:00
|
|
|
}];
|
|
|
|
|
|
2015-06-19 15:09:15 -03:00
|
|
|
self.setOngoingProcess = function(processName, isOn) {
|
2015-03-06 12:00:10 -03:00
|
|
|
$log.debug('onGoingProcess', processName, isOn);
|
|
|
|
|
self[processName] = isOn;
|
|
|
|
|
self.onGoingProcess[processName] = isOn;
|
|
|
|
|
|
|
|
|
|
var name;
|
|
|
|
|
self.anyOnGoingProcess = lodash.any(self.onGoingProcess, function(isOn, processName) {
|
|
|
|
|
if (isOn)
|
|
|
|
|
name = name || processName;
|
|
|
|
|
return isOn;
|
|
|
|
|
});
|
|
|
|
|
// The first one
|
|
|
|
|
self.onGoingProcessName = name;
|
2015-04-14 12:51:49 -03:00
|
|
|
$timeout(function() {
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.setFocusedWallet = function() {
|
|
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
if (!fc) return;
|
|
|
|
|
|
2015-04-15 13:39:48 -03:00
|
|
|
// Clean status
|
|
|
|
|
self.lockedBalance = null;
|
2015-05-30 23:01:45 -03:00
|
|
|
self.availableBalanceStr = null;
|
|
|
|
|
self.totalBalanceStr = null;
|
|
|
|
|
self.lockedBalanceStr = null;
|
2015-04-15 13:39:48 -03:00
|
|
|
self.totalBalanceStr = null;
|
|
|
|
|
self.alternativeBalanceAvailable = false;
|
|
|
|
|
self.totalBalanceAlternative = null;
|
|
|
|
|
self.notAuthorized = false;
|
|
|
|
|
self.txHistory = [];
|
|
|
|
|
self.txHistoryPaging = false;
|
2015-04-24 02:46:29 -03:00
|
|
|
self.pendingTxProposalsCountForUs = null;
|
2015-03-06 12:00:10 -03:00
|
|
|
$timeout(function() {
|
|
|
|
|
self.hasProfile = true;
|
|
|
|
|
self.noFocusedWallet = false;
|
|
|
|
|
self.onGoingProcess = {};
|
|
|
|
|
|
2015-04-29 12:16:28 -03:00
|
|
|
// Credentials Shortcuts
|
2015-03-06 12:00:10 -03:00
|
|
|
self.m = fc.credentials.m;
|
|
|
|
|
self.n = fc.credentials.n;
|
|
|
|
|
self.network = fc.credentials.network;
|
|
|
|
|
self.copayerId = fc.credentials.copayerId;
|
|
|
|
|
self.copayerName = fc.credentials.copayerName;
|
|
|
|
|
self.requiresMultipleSignatures = fc.credentials.m > 1;
|
|
|
|
|
self.isShared = fc.credentials.n > 1;
|
|
|
|
|
self.walletName = fc.credentials.walletName;
|
|
|
|
|
self.walletId = fc.credentials.walletId;
|
|
|
|
|
self.isComplete = fc.isComplete();
|
2015-07-15 22:10:59 -03:00
|
|
|
self.canSign = fc.canSign();
|
2015-03-06 12:00:10 -03:00
|
|
|
self.txps = [];
|
|
|
|
|
self.copayers = [];
|
2015-04-28 20:13:28 -03:00
|
|
|
self.updateColor();
|
2015-05-14 10:39:22 -03:00
|
|
|
self.updateAlias();
|
2015-03-06 12:00:10 -03:00
|
|
|
|
|
|
|
|
storageService.getBackupFlag(self.walletId, function(err, val) {
|
2015-04-26 20:30:09 -03:00
|
|
|
self.needsBackup = self.network == 'testnet' ? false : !val;
|
2015-03-06 12:00:10 -03:00
|
|
|
self.openWallet();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2015-04-28 20:13:28 -03:00
|
|
|
self.setTab = function(tab, reset, tries) {
|
|
|
|
|
tries = tries || 0;
|
|
|
|
|
if (self.tab === tab && !reset)
|
2015-04-23 16:17:18 -03:00
|
|
|
return;
|
|
|
|
|
|
2015-05-04 12:23:43 -03:00
|
|
|
if (!document.getElementById('menu-' + tab) && ++tries < 5) {
|
2015-04-28 20:13:28 -03:00
|
|
|
return $timeout(function() {
|
2015-05-04 12:23:43 -03:00
|
|
|
self.setTab(tab, reset, tries);
|
2015-04-28 20:13:28 -03:00
|
|
|
}, 300);
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-23 16:17:18 -03:00
|
|
|
if (!self.tab)
|
|
|
|
|
self.tab = 'walletHome';
|
|
|
|
|
|
|
|
|
|
if (document.getElementById(self.tab)) {
|
2015-04-23 15:19:30 -03:00
|
|
|
document.getElementById(self.tab).className = 'tab-out tab-view ' + self.tab;
|
|
|
|
|
var old = document.getElementById('menu-' + self.tab);
|
2015-04-23 16:17:18 -03:00
|
|
|
if (old) {
|
|
|
|
|
old.className = '';
|
|
|
|
|
}
|
2015-04-23 15:19:30 -03:00
|
|
|
}
|
2015-04-23 14:12:32 -03:00
|
|
|
|
2015-04-23 15:19:30 -03:00
|
|
|
if (document.getElementById(tab)) {
|
|
|
|
|
document.getElementById(tab).className = 'tab-in tab-view ' + tab;
|
|
|
|
|
var newe = document.getElementById('menu-' + tab);
|
2015-04-23 18:05:31 -03:00
|
|
|
if (newe) {
|
|
|
|
|
newe.className = 'active';
|
|
|
|
|
}
|
2015-04-23 15:19:30 -03:00
|
|
|
}
|
2015-04-23 14:12:32 -03:00
|
|
|
|
2015-04-23 13:12:30 -03:00
|
|
|
self.tab = tab;
|
2015-04-23 15:19:30 -03:00
|
|
|
$rootScope.$emit('Local/TabChanged', tab);
|
2015-04-23 13:12:30 -03:00
|
|
|
};
|
|
|
|
|
|
2015-05-19 14:10:47 -03:00
|
|
|
|
2015-06-29 21:46:34 -03:00
|
|
|
self._updateRemotePreferencesFor = function(clients, prefs, cb) {
|
|
|
|
|
var client = clients.shift();
|
|
|
|
|
|
|
|
|
|
if (!client)
|
|
|
|
|
return cb();
|
|
|
|
|
|
|
|
|
|
$log.debug('Saving remote preferences', client.credentials.walletName, prefs);
|
|
|
|
|
client.savePreferences(prefs, function(err) {
|
2015-06-30 18:38:45 -03:00
|
|
|
// we ignore errors here
|
|
|
|
|
if (err) $log.warn(err);
|
2015-06-29 21:46:34 -03:00
|
|
|
|
|
|
|
|
self._updateRemotePreferencesFor(clients, prefs, cb);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.updateRemotePreferences = function(opts, cb) {
|
|
|
|
|
var prefs = opts.preferences || {};
|
2015-05-19 14:10:47 -03:00
|
|
|
var fc = profileService.focusedClient;
|
2015-06-29 21:46:34 -03:00
|
|
|
|
2015-06-29 22:40:39 -03:00
|
|
|
// Update this JIC.
|
|
|
|
|
var config = configService.getSync().wallet.settings;
|
|
|
|
|
|
2015-06-29 21:46:34 -03:00
|
|
|
//prefs.email (may come from arguments)
|
|
|
|
|
prefs.language = self.defaultLanguageIsoCode;
|
2015-07-01 11:00:43 -03:00
|
|
|
prefs.unit = config.unitCode;
|
2015-06-29 21:46:34 -03:00
|
|
|
|
|
|
|
|
var clients = [];
|
|
|
|
|
if (opts.saveAll) {
|
|
|
|
|
clients = lodash.values(profileService.walletClients);
|
|
|
|
|
} else {
|
|
|
|
|
clients = [fc];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self._updateRemotePreferencesFor(clients, prefs, function(err) {
|
2015-06-30 18:38:45 -03:00
|
|
|
if (err) return cb(err);
|
2015-06-29 22:40:39 -03:00
|
|
|
if (!fc) return cb();
|
2015-06-29 21:46:34 -03:00
|
|
|
|
|
|
|
|
fc.getPreferences(function(err, preferences) {
|
|
|
|
|
if (err) {
|
|
|
|
|
return cb(err);
|
|
|
|
|
}
|
|
|
|
|
self.preferences = preferences;
|
|
|
|
|
return cb();
|
|
|
|
|
});
|
2015-05-19 14:10:47 -03:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-30 14:28:18 -03:00
|
|
|
var _walletStatusHash = function(walletStatus) {
|
2015-05-30 22:38:08 -03:00
|
|
|
var bal;
|
2015-05-30 14:28:18 -03:00
|
|
|
if (walletStatus) {
|
2015-05-30 22:38:08 -03:00
|
|
|
bal = walletStatus.balance.totalAmount;
|
2015-05-30 14:28:18 -03:00
|
|
|
} else {
|
2015-05-30 22:38:08 -03:00
|
|
|
bal = self.totalBalanceSat;
|
2015-05-30 14:28:18 -03:00
|
|
|
}
|
2015-05-30 22:38:08 -03:00
|
|
|
return bal;
|
2015-05-30 14:28:18 -03:00
|
|
|
};
|
2015-05-19 14:10:47 -03:00
|
|
|
|
2015-06-13 02:01:02 -03:00
|
|
|
self.updateAll = function(opts, initStatusHash, tries) {
|
2015-05-18 16:21:36 -03:00
|
|
|
tries = tries || 0;
|
2015-06-19 15:09:15 -03:00
|
|
|
opts = opts || {};
|
|
|
|
|
|
|
|
|
|
if (opts.untilItChanges && lodash.isUndefined(initStatusHash)) {
|
2015-05-30 14:28:18 -03:00
|
|
|
initStatusHash = _walletStatusHash();
|
2015-05-30 22:38:08 -03:00
|
|
|
$log.debug('Updating status until it changes. initStatusHash:' + initStatusHash)
|
2015-05-18 16:21:36 -03:00
|
|
|
}
|
2015-03-06 12:00:10 -03:00
|
|
|
var get = function(cb) {
|
2015-06-19 15:09:15 -03:00
|
|
|
if (opts.walletStatus)
|
2015-06-13 02:01:02 -03:00
|
|
|
return cb(null, opts.walletStatus);
|
2015-04-13 14:58:07 -03:00
|
|
|
else {
|
|
|
|
|
self.updateError = false;
|
|
|
|
|
return fc.getStatus(function(err, ret) {
|
2015-04-15 14:03:38 -03:00
|
|
|
if (err) {
|
|
|
|
|
self.updateError = true;
|
|
|
|
|
} else {
|
2015-06-19 15:09:15 -03:00
|
|
|
if (!opts.quiet)
|
|
|
|
|
self.setOngoingProcess('scanning', ret.wallet.scanning);
|
2015-04-15 14:03:38 -03:00
|
|
|
}
|
2015-04-13 14:58:07 -03:00
|
|
|
return cb(err, ret);
|
|
|
|
|
});
|
|
|
|
|
}
|
2015-03-06 12:00:10 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
if (!fc) return;
|
|
|
|
|
|
|
|
|
|
$timeout(function() {
|
2015-06-19 15:09:15 -03:00
|
|
|
|
|
|
|
|
if (!opts.quiet)
|
|
|
|
|
self.setOngoingProcess('updatingStatus', true);
|
|
|
|
|
|
2015-05-29 12:39:17 -03:00
|
|
|
$log.debug('Updating Status:', fc, tries);
|
2015-03-06 12:00:10 -03:00
|
|
|
get(function(err, walletStatus) {
|
2015-06-29 21:46:34 -03:00
|
|
|
var currentStatusHash = _walletStatusHash(walletStatus);
|
|
|
|
|
$log.debug('Status update. hash:' + currentStatusHash + ' Try:' + tries);
|
2015-06-19 15:09:15 -03:00
|
|
|
if (!err && opts.untilItChanges && initStatusHash == currentStatusHash && tries < 7) {
|
2015-05-18 16:21:36 -03:00
|
|
|
return $timeout(function() {
|
2015-05-30 22:38:08 -03:00
|
|
|
$log.debug('Retrying update... Try:' + tries)
|
2015-06-29 21:46:34 -03:00
|
|
|
return self.updateAll({
|
|
|
|
|
walletStatus: null,
|
2015-07-13 13:09:52 -03:00
|
|
|
untilItChanges: true,
|
|
|
|
|
triggerTxUpdate: opts.triggerTxUpdate,
|
2015-06-29 21:46:34 -03:00
|
|
|
}, initStatusHash, ++tries);
|
2015-05-29 12:39:17 -03:00
|
|
|
}, 1400 * tries);
|
2015-05-18 16:21:36 -03:00
|
|
|
}
|
2015-06-19 15:09:15 -03:00
|
|
|
if (!opts.quiet)
|
|
|
|
|
self.setOngoingProcess('updatingStatus', false);
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
if (err) {
|
|
|
|
|
self.handleError(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$log.debug('Wallet Status:', walletStatus);
|
|
|
|
|
self.setPendingTxps(walletStatus.pendingTxps);
|
|
|
|
|
|
|
|
|
|
// Status Shortcuts
|
|
|
|
|
self.walletName = walletStatus.wallet.name;
|
|
|
|
|
self.walletSecret = walletStatus.wallet.secret;
|
|
|
|
|
self.walletStatus = walletStatus.wallet.status;
|
2015-04-15 14:03:38 -03:00
|
|
|
self.walletScanStatus = walletStatus.wallet.scanStatus;
|
2015-03-06 12:00:10 -03:00
|
|
|
self.copayers = walletStatus.wallet.copayers;
|
2015-05-19 14:10:47 -03:00
|
|
|
self.preferences = walletStatus.preferences;
|
2015-03-06 12:00:10 -03:00
|
|
|
self.setBalance(walletStatus.balance);
|
2015-06-27 13:48:25 -03:00
|
|
|
self.otherWallets = lodash.filter(profileService.getWallets(self.network), function(w) {
|
|
|
|
|
return w.id != self.walletId;
|
|
|
|
|
});;
|
2015-07-13 22:25:34 +03:00
|
|
|
|
|
|
|
|
// Notify external addons or plugins
|
|
|
|
|
$rootScope.$emit('Local/BalanceUpdated', walletStatus.balance);
|
|
|
|
|
|
2015-04-21 17:49:17 -03:00
|
|
|
$rootScope.$apply();
|
2015-07-06 10:40:40 -03:00
|
|
|
|
|
|
|
|
if (opts.triggerTxUpdate) {
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
self.updateTxHistory();
|
|
|
|
|
}, 1);
|
|
|
|
|
}
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.updateBalance = function() {
|
|
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
self.setOngoingProcess('updatingBalance', true);
|
|
|
|
|
$log.debug('Updating Balance');
|
|
|
|
|
fc.getBalance(function(err, balance) {
|
|
|
|
|
self.setOngoingProcess('updatingBalance', false);
|
|
|
|
|
if (err) {
|
|
|
|
|
$log.debug('Wallet Balance ERROR:', err);
|
|
|
|
|
$scope.$emit('Local/ClientError', err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$log.debug('Wallet Balance:', balance);
|
|
|
|
|
self.setBalance(balance);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.updatePendingTxps = function() {
|
|
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
self.setOngoingProcess('updatingPendingTxps', true);
|
|
|
|
|
$log.debug('Updating PendingTxps');
|
2015-04-18 07:08:08 -03:00
|
|
|
fc.getTxProposals({}, function(err, txps) {
|
2015-03-06 12:00:10 -03:00
|
|
|
self.setOngoingProcess('updatingPendingTxps', false);
|
|
|
|
|
if (err) {
|
|
|
|
|
$log.debug('Wallet PendingTxps ERROR:', err);
|
|
|
|
|
$scope.$emit('Local/ClientError', err);
|
|
|
|
|
} else {
|
|
|
|
|
$log.debug('Wallet PendingTxps:', txps);
|
|
|
|
|
self.setPendingTxps(txps);
|
|
|
|
|
}
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.updateTxHistory = function(skip) {
|
|
|
|
|
var fc = profileService.focusedClient;
|
2015-04-24 03:26:57 -03:00
|
|
|
if (!fc.isComplete()) return;
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
if (!skip) {
|
|
|
|
|
self.txHistory = [];
|
|
|
|
|
}
|
|
|
|
|
self.skipHistory = skip || 0;
|
2015-04-24 02:42:10 -03:00
|
|
|
$log.debug('Updating Transaction History');
|
|
|
|
|
self.txHistoryError = false;
|
|
|
|
|
self.updatingTxHistory = true;
|
2015-04-24 03:01:26 -03:00
|
|
|
self.txHistoryPaging = false;
|
2015-03-06 12:00:10 -03:00
|
|
|
$timeout(function() {
|
|
|
|
|
fc.getTxHistory({
|
|
|
|
|
skip: self.skipHistory,
|
|
|
|
|
limit: self.limitHistory + 1
|
|
|
|
|
}, function(err, txs) {
|
2015-04-14 12:51:49 -03:00
|
|
|
self.updatingTxHistory = false;
|
2015-03-06 12:00:10 -03:00
|
|
|
if (err) {
|
|
|
|
|
$log.debug('TxHistory ERROR:', err);
|
2015-05-15 11:07:19 -03:00
|
|
|
// We do not should errors here, since history is usually
|
|
|
|
|
// fetched AFTER others requests.
|
|
|
|
|
//self.handleError(err);
|
2015-04-13 14:58:07 -03:00
|
|
|
self.txHistoryError = true;
|
|
|
|
|
} else {
|
2015-03-06 12:00:10 -03:00
|
|
|
$log.debug('Wallet Transaction History:', txs);
|
|
|
|
|
self.skipHistory = self.skipHistory + self.limitHistory;
|
|
|
|
|
self.setTxHistory(txs);
|
|
|
|
|
}
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.handleError = function(err) {
|
2015-04-27 14:14:51 -03:00
|
|
|
$log.warn('Client ERROR:', err);
|
2015-03-06 12:00:10 -03:00
|
|
|
if (err.code === 'NOTAUTHORIZED') {
|
|
|
|
|
$scope.$emit('Local/NotAuthorized');
|
|
|
|
|
} else if (err.code === 'NOTFOUND') {
|
|
|
|
|
$scope.$emit('Local/BWSNotFound');
|
|
|
|
|
} else {
|
2015-04-27 14:18:22 -03:00
|
|
|
$scope.$emit('Local/ClientError', (err.error ? err.error : err));
|
2015-03-06 12:00:10 -03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
self.openWallet = function() {
|
|
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
$timeout(function() {
|
2015-04-23 15:32:11 -03:00
|
|
|
$rootScope.$apply();
|
2015-03-06 12:00:10 -03:00
|
|
|
self.setOngoingProcess('openingWallet', true);
|
2015-04-14 16:06:04 -03:00
|
|
|
self.updateError = false;
|
2015-03-06 12:00:10 -03:00
|
|
|
fc.openWallet(function(err, walletStatus) {
|
|
|
|
|
self.setOngoingProcess('openingWallet', false);
|
|
|
|
|
if (err) {
|
2015-04-14 16:06:04 -03:00
|
|
|
self.updateError = true;
|
2015-03-06 12:00:10 -03:00
|
|
|
self.handleError(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$log.debug('Wallet Opened');
|
2015-06-29 21:46:34 -03:00
|
|
|
self.updateAll(lodash.isObject(walletStatus) ? {
|
|
|
|
|
walletStatus: walletStatus
|
|
|
|
|
} : null);
|
2015-03-06 12:00:10 -03:00
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.setPendingTxps = function(txps) {
|
|
|
|
|
var config = configService.getSync().wallet.settings;
|
|
|
|
|
self.pendingTxProposalsCountForUs = 0;
|
|
|
|
|
lodash.each(txps, function(tx) {
|
|
|
|
|
var amount = tx.amount * self.satToUnit;
|
|
|
|
|
tx.amountStr = profileService.formatAmount(tx.amount) + ' ' + config.unitName;
|
2015-06-22 11:33:53 -03:00
|
|
|
tx.feeStr = profileService.formatAmount(tx.fee) + ' ' + config.unitName;
|
2015-03-06 12:00:10 -03:00
|
|
|
tx.alternativeAmount = rateService.toFiat(tx.amount, config.alternativeIsoCode) ? rateService.toFiat(tx.amount, config.alternativeIsoCode).toFixed(2) : 'N/A';
|
|
|
|
|
tx.alternativeAmountStr = tx.alternativeAmount + " " + config.alternativeIsoCode;
|
|
|
|
|
tx.alternativeIsoCode = config.alternativeIsoCode;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var action = lodash.find(tx.actions, {
|
|
|
|
|
copayerId: self.copayerId
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!action && tx.status == 'pending') {
|
|
|
|
|
tx.pendingForUs = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action && action.type == 'accept') {
|
|
|
|
|
tx.statusForUs = 'accepted';
|
|
|
|
|
} else if (action && action.type == 'reject') {
|
|
|
|
|
tx.statusForUs = 'rejected';
|
|
|
|
|
} else {
|
|
|
|
|
tx.statusForUs = 'pending';
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-18 11:17:35 -03:00
|
|
|
if (!tx.deleteLockTime)
|
|
|
|
|
tx.canBeRemoved = true;
|
2015-03-06 12:00:10 -03:00
|
|
|
|
|
|
|
|
if (tx.creatorId != self.copayerId) {
|
|
|
|
|
self.pendingTxProposalsCountForUs = self.pendingTxProposalsCountForUs + 1;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
self.txps = txps;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.setTxHistory = function(txs) {
|
2015-07-17 14:30:55 -03:00
|
|
|
var config = configService.getSync().wallet.settings;
|
2015-07-13 13:31:05 -03:00
|
|
|
var now = Math.floor(Date.now() / 1000);
|
2015-03-06 12:00:10 -03:00
|
|
|
var c = 0;
|
|
|
|
|
self.txHistoryPaging = txs[self.limitHistory] ? true : false;
|
|
|
|
|
lodash.each(txs, function(tx) {
|
2015-07-13 13:31:05 -03:00
|
|
|
|
|
|
|
|
// no future transactions...
|
|
|
|
|
if (tx.time > now)
|
|
|
|
|
tx.time = now;
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
tx.rateTs = Math.floor((tx.ts || now) / 1000);
|
|
|
|
|
tx.amountStr = profileService.formatAmount(tx.amount); //$filter('noFractionNumber')(
|
2015-07-17 14:30:55 -03:00
|
|
|
if (tx.fees)
|
|
|
|
|
tx.feeStr = profileService.formatAmount(tx.fees) + ' ' + config.unitName;
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
if (c < self.limitHistory) {
|
|
|
|
|
self.txHistory.push(tx);
|
|
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-14 10:39:22 -03:00
|
|
|
self.updateAlias = function() {
|
|
|
|
|
var config = configService.getSync();
|
|
|
|
|
config.aliasFor = config.aliasFor || {};
|
|
|
|
|
self.alias = config.aliasFor[self.walletId];
|
|
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
fc.alias = self.alias;
|
|
|
|
|
};
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
self.updateColor = function() {
|
|
|
|
|
var config = configService.getSync();
|
|
|
|
|
config.colorFor = config.colorFor || {};
|
2015-05-29 15:25:41 -03:00
|
|
|
self.backgroundColor = config.colorFor[self.walletId] || '#4A90E2';
|
2015-03-06 12:00:10 -03:00
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
fc.backgroundColor = self.backgroundColor;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.setBalance = function(balance) {
|
|
|
|
|
if (!balance) return;
|
|
|
|
|
var config = configService.getSync().wallet.settings;
|
|
|
|
|
var COIN = 1e8;
|
|
|
|
|
|
|
|
|
|
// Address with Balance
|
|
|
|
|
self.balanceByAddress = balance.byAddress;
|
|
|
|
|
|
|
|
|
|
// SAT
|
|
|
|
|
self.totalBalanceSat = balance.totalAmount;
|
|
|
|
|
self.lockedBalanceSat = balance.lockedAmount;
|
|
|
|
|
self.availableBalanceSat = self.totalBalanceSat - self.lockedBalanceSat;
|
|
|
|
|
|
|
|
|
|
// Selected unit
|
|
|
|
|
self.unitToSatoshi = config.unitToSatoshi;
|
|
|
|
|
self.satToUnit = 1 / self.unitToSatoshi;
|
|
|
|
|
self.unitName = config.unitName;
|
|
|
|
|
|
|
|
|
|
self.totalBalance = strip(self.totalBalanceSat * self.satToUnit);
|
|
|
|
|
self.lockedBalance = strip(self.lockedBalanceSat * self.satToUnit);
|
|
|
|
|
self.availableBalance = strip(self.availableBalanceSat * self.satToUnit);
|
|
|
|
|
|
|
|
|
|
// BTC
|
|
|
|
|
self.totalBalanceBTC = strip(self.totalBalanceSat / COIN);
|
|
|
|
|
self.lockedBalanceBTC = strip(self.lockedBalanceSat / COIN);
|
|
|
|
|
self.availableBalanceBTC = strip(self.availableBalanceBTC / COIN);
|
|
|
|
|
|
2015-06-19 15:00:27 -03:00
|
|
|
// KB to send max
|
2015-06-19 17:22:12 -03:00
|
|
|
self.feePerKbSat = config.feeValue || 10000;
|
2015-06-19 15:09:15 -03:00
|
|
|
if (balance.totalKbToSendMax) {
|
|
|
|
|
var feeToSendMaxSat = balance.totalKbToSendMax * self.feePerKbSat;
|
2015-06-19 15:00:27 -03:00
|
|
|
|
2015-06-19 15:09:15 -03:00
|
|
|
self.availableMaxBalance = strip((self.availableBalanceSat - feeToSendMaxSat) * self.satToUnit);
|
|
|
|
|
self.feeToSendMaxStr = profileService.formatAmount(feeToSendMaxSat) + ' ' + self.unitName;
|
|
|
|
|
} else {
|
|
|
|
|
self.feeToSendMaxStr = null;
|
|
|
|
|
}
|
2015-03-06 12:00:10 -03:00
|
|
|
|
|
|
|
|
//STR
|
|
|
|
|
self.totalBalanceStr = profileService.formatAmount(self.totalBalanceSat) + ' ' + self.unitName;
|
|
|
|
|
self.lockedBalanceStr = profileService.formatAmount(self.lockedBalanceSat) + ' ' + self.unitName;
|
|
|
|
|
self.availableBalanceStr = profileService.formatAmount(self.availableBalanceSat) + ' ' + self.unitName;
|
|
|
|
|
|
|
|
|
|
self.alternativeName = config.alternativeName;
|
|
|
|
|
self.alternativeIsoCode = config.alternativeIsoCode;
|
|
|
|
|
|
|
|
|
|
// Check address
|
2015-06-29 21:46:34 -03:00
|
|
|
addressService.isUsed(self.walletId, balance.byAddress, function(err, used) {
|
|
|
|
|
if (used) {
|
2015-06-27 13:22:56 -03:00
|
|
|
$log.debug('Address used. Creating new');
|
|
|
|
|
$rootScope.$emit('Local/NeedNewAddress');
|
|
|
|
|
}
|
|
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
|
|
|
|
|
rateService.whenAvailable(function() {
|
|
|
|
|
|
|
|
|
|
var totalBalanceAlternative = rateService.toFiat(self.totalBalance * self.unitToSatoshi, self.alternativeIsoCode);
|
|
|
|
|
var lockedBalanceAlternative = rateService.toFiat(self.lockedBalance * self.unitToSatoshi, self.alternativeIsoCode);
|
|
|
|
|
var alternativeConversionRate = rateService.toFiat(100000000, self.alternativeIsoCode);
|
|
|
|
|
|
|
|
|
|
self.totalBalanceAlternative = $filter('noFractionNumber')(totalBalanceAlternative, 2);
|
|
|
|
|
self.lockedBalanceAlternative = $filter('noFractionNumber')(lockedBalanceAlternative, 2);
|
|
|
|
|
self.alternativeConversionRate = $filter('noFractionNumber')(alternativeConversionRate, 2);
|
|
|
|
|
|
|
|
|
|
self.alternativeBalanceAvailable = true;
|
|
|
|
|
self.updatingBalance = false;
|
|
|
|
|
|
|
|
|
|
self.isRateAvailable = true;
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!rateService.isAvailable()) {
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-03 15:35:34 -03:00
|
|
|
this.csvHistory = function() {
|
|
|
|
|
|
2015-07-07 23:56:49 -03:00
|
|
|
function saveFile(name, data) {
|
2015-07-07 13:24:18 -03:00
|
|
|
var chooser = document.querySelector(name);
|
|
|
|
|
chooser.addEventListener("change", function(evt) {
|
2015-07-07 23:56:49 -03:00
|
|
|
var fs = require('fs');
|
2015-07-07 13:24:18 -03:00
|
|
|
fs.writeFile(this.value, data, function(err) {
|
2015-07-07 23:56:49 -03:00
|
|
|
if (err) {
|
2015-07-14 11:16:54 -03:00
|
|
|
$log.debug(err);
|
2015-07-07 13:24:18 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}, false);
|
Addon support
Addons are simple Angular modules with views, controllers, services etc. Addons can register
themselves in Copay using pluginManagerProvider. It allows them to add extra items to the bottom
menu and as well as extra tab-views:
````
addonManagerProvider.registerAddon({
menuItem: {
'title': 'Assets',
'icon': 'icon-pricetag',
'link': 'assets'
},
view: {
id: 'assets',
'class': 'assets',
template: 'colored-coins/views/assets.html'
}
});
````
Addons can consume core Copay services and listen for events to react on changes. For this very
first addon system inplementation Copay emits additional BalanceUpdated event so that interested
addons can react on new transactions (see plugin reference implementation below).
As bottom menu can accomodate only 6 items without sacrificing usability, so it was reworked to
have second layer of items. Now If menu has more than 6 items, toggle button will be added to
the menu allowing to reveal extra items in a sliding panel. Bottom menu in this case will show
only 5 items, the rest will be rendered on sliding panel.
This changes addresses issue #2949 and reference implementation of addon could be found here:
https://github.com/troggy/copay-colored-coins-plugin
2015-07-04 13:02:46 +03:00
|
|
|
chooser.click();
|
2015-07-07 13:24:18 -03:00
|
|
|
}
|
|
|
|
|
|
2015-07-03 15:35:34 -03:00
|
|
|
function formatDate(date) {
|
|
|
|
|
var dateObj = new Date(date);
|
|
|
|
|
if (!dateObj) {
|
2015-07-14 11:16:54 -03:00
|
|
|
$log.debug('Error formating a date');
|
2015-07-03 15:35:34 -03:00
|
|
|
return 'DateError'
|
|
|
|
|
}
|
|
|
|
|
if (!dateObj.toJSON()) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 16:31:54 -03:00
|
|
|
return dateObj.toJSON();
|
2015-07-03 15:35:34 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatString(str) {
|
|
|
|
|
if (!str) return '';
|
|
|
|
|
|
|
|
|
|
if (str.indexOf('"') !== -1) {
|
|
|
|
|
//replace all
|
|
|
|
|
str = str.replace(new RegExp('"', 'g'), '\'');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//escaping commas
|
|
|
|
|
str = '\"' + str + '\"';
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-14 11:16:54 -03:00
|
|
|
function getHistory(skip, cb) {
|
|
|
|
|
skip = skip || 0;
|
|
|
|
|
fc.getTxHistory({
|
|
|
|
|
skip: skip,
|
|
|
|
|
limit: 100
|
|
|
|
|
}, function(err, txs) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
if (txs && txs.length > 0) {
|
|
|
|
|
allTxs.push(txs);
|
2015-07-14 12:19:22 -03:00
|
|
|
return getHistory(skip + 100, cb);
|
2015-07-14 11:16:54 -03:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return cb(null, lodash.flatten(allTxs));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-03 15:35:34 -03:00
|
|
|
if (isCordova) {
|
2015-07-14 11:16:54 -03:00
|
|
|
$log.info('Not available on mobile');
|
2015-07-03 15:35:34 -03:00
|
|
|
return;
|
|
|
|
|
}
|
2015-07-07 23:56:49 -03:00
|
|
|
var isNode = nodeWebkit.isDefined();
|
2015-07-03 15:35:34 -03:00
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
if (!fc.isComplete()) return;
|
|
|
|
|
var self = this;
|
2015-07-14 11:16:54 -03:00
|
|
|
var allTxs = [];
|
2015-07-03 15:35:34 -03:00
|
|
|
$log.debug('Generating CSV from History');
|
|
|
|
|
self.setOngoingProcess('generatingCSV', true);
|
|
|
|
|
$timeout(function() {
|
2015-07-14 11:16:54 -03:00
|
|
|
getHistory(null, function(err, txs) {
|
2015-07-03 15:35:34 -03:00
|
|
|
self.setOngoingProcess('generatingCSV', false);
|
|
|
|
|
if (err) {
|
|
|
|
|
$log.debug('TxHistory ERROR:', err);
|
|
|
|
|
} else {
|
|
|
|
|
$log.debug('Wallet Transaction History:', txs);
|
|
|
|
|
|
|
|
|
|
self.satToUnit = 1 / self.unitToSatoshi;
|
|
|
|
|
var data = txs;
|
2015-07-06 16:31:54 -03:00
|
|
|
var satToBtc = 1 / 100000000;
|
2015-07-07 13:48:45 -03:00
|
|
|
var filename = 'Copay-' + (self.alias || self.walletName ) + '.csv';
|
2015-07-07 23:56:49 -03:00
|
|
|
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';
|
2015-07-03 15:35:34 -03:00
|
|
|
|
2015-07-14 16:47:23 -03:00
|
|
|
var _amount, _note;
|
2015-07-07 23:56:49 -03:00
|
|
|
var dataString;
|
2015-07-03 15:35:34 -03:00
|
|
|
data.forEach(function(it, index) {
|
2015-07-07 23:56:49 -03:00
|
|
|
_amount = (it.action == 'sent' ? '-' : '') + (it.amount * satToBtc).toFixed(8);
|
2015-07-14 16:47:23 -03:00
|
|
|
_note = formatString((it.message ? 'Note: ' + it.message + ' - ' : '') + 'TxId: ' + it.txid);
|
|
|
|
|
dataString = formatDate(it.time * 1000) + ',' + formatString(it.addressTo) + ',' + _note + ',' + _amount + ',BTC,,,,';
|
2015-07-03 15:35:34 -03:00
|
|
|
csvContent += index < data.length ? dataString + "\n" : dataString;
|
|
|
|
|
});
|
|
|
|
|
|
2015-07-07 23:56:49 -03:00
|
|
|
if (isNode) {
|
|
|
|
|
saveFile('#export_file', csvContent);
|
2015-07-07 13:24:18 -03:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
var encodedUri = encodeURI(csvContent);
|
|
|
|
|
var link = document.createElement("a");
|
|
|
|
|
link.setAttribute("href", encodedUri);
|
|
|
|
|
link.setAttribute("download", filename);
|
|
|
|
|
link.click();
|
|
|
|
|
}
|
2015-07-03 15:35:34 -03:00
|
|
|
}
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
2015-03-06 12:00:10 -03:00
|
|
|
|
2015-04-26 20:30:09 -03:00
|
|
|
self.clientError = function(err) {
|
2015-04-23 23:51:21 -03:00
|
|
|
if (isCordova) {
|
|
|
|
|
navigator.notification.confirm(
|
|
|
|
|
err,
|
|
|
|
|
function() {},
|
|
|
|
|
'Wallet Server Error', ['OK']
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
alert(err);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-03-06 12:00:10 -03:00
|
|
|
|
2015-04-26 20:30:09 -03:00
|
|
|
self.deviceError = function(err) {
|
2015-04-24 16:39:12 -03:00
|
|
|
if (isCordova) {
|
|
|
|
|
navigator.notification.confirm(
|
|
|
|
|
err,
|
|
|
|
|
function() {},
|
|
|
|
|
'Device Error', ['OK']
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
alert(err);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
self.recreate = function(cb) {
|
|
|
|
|
var fc = profileService.focusedClient;
|
|
|
|
|
self.setOngoingProcess('recreating', true);
|
|
|
|
|
fc.recreateWallet(function(err) {
|
|
|
|
|
self.notAuthorized = false;
|
|
|
|
|
self.setOngoingProcess('recreating', false);
|
|
|
|
|
|
2015-04-14 12:51:49 -03:00
|
|
|
if (err) {
|
2015-04-27 14:14:51 -03:00
|
|
|
self.handleError(err);
|
2015-04-14 12:51:49 -03:00
|
|
|
$rootScope.$apply();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
profileService.setWalletClients();
|
2015-04-18 07:23:11 -03:00
|
|
|
$timeout(function() {
|
|
|
|
|
$rootScope.$emit('Local/WalletImported', self.walletId);
|
|
|
|
|
}, 100);
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.openMenu = function() {
|
|
|
|
|
go.swipe(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.closeMenu = function() {
|
|
|
|
|
go.swipe();
|
|
|
|
|
};
|
|
|
|
|
|
2015-04-15 14:03:38 -03:00
|
|
|
self.retryScan = function() {
|
|
|
|
|
var self = this;
|
|
|
|
|
self.startScan(self.walletId);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
self.startScan = function(walletId) {
|
|
|
|
|
var c = profileService.walletClients[walletId];
|
|
|
|
|
|
|
|
|
|
if (self.walletId == walletId)
|
|
|
|
|
self.setOngoingProcess('scanning', true);
|
|
|
|
|
|
|
|
|
|
c.startScan({
|
|
|
|
|
includeCopayerBranches: true,
|
|
|
|
|
}, function(err) {
|
2015-06-10 11:12:41 -03:00
|
|
|
if (err && self.walletId == walletId) {
|
|
|
|
|
self.setOngoingProcess('scanning', false);
|
2015-04-27 14:14:51 -03:00
|
|
|
self.handleError(err);
|
2015-04-14 12:51:49 -03:00
|
|
|
$rootScope.$apply();
|
2015-03-06 12:00:10 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-29 21:46:34 -03:00
|
|
|
self.setUxLanguage = function() {
|
|
|
|
|
var userLang = configService.getSync().wallet.settings.defaultLanguage;
|
|
|
|
|
if (!userLang) {
|
|
|
|
|
// Auto-detect browser language
|
|
|
|
|
var androidLang;
|
2015-04-22 18:41:30 -03:00
|
|
|
|
2015-06-29 21:46:34 -03:00
|
|
|
if (navigator && navigator.userAgent && (androidLang = navigator.userAgent.match(/android.*\W(\w\w)-(\w\w)\W/i))) {
|
|
|
|
|
userLang = androidLang[1];
|
|
|
|
|
} else {
|
|
|
|
|
// works for iOS and Android 4.x
|
|
|
|
|
userLang = navigator.userLanguage || navigator.language;
|
2015-04-22 18:41:30 -03:00
|
|
|
}
|
2015-06-29 21:46:34 -03:00
|
|
|
userLang = userLang ? (userLang.split('-', 1)[0] || 'en') : 'en';
|
|
|
|
|
}
|
|
|
|
|
if (userLang != gettextCatalog.getCurrentLanguage()) {
|
|
|
|
|
$log.debug('Setting default language: ' + userLang);
|
|
|
|
|
gettextCatalog.setCurrentLanguage(userLang);
|
|
|
|
|
amMoment.changeLocale(userLang);
|
2015-04-22 18:41:30 -03:00
|
|
|
}
|
2015-06-29 21:46:34 -03:00
|
|
|
|
|
|
|
|
self.defaultLanguageIsoCode = userLang;
|
2015-04-23 15:19:30 -03:00
|
|
|
self.defaultLanguageName = lodash.result(lodash.find(self.availableLanguages, {
|
|
|
|
|
'isoCode': self.defaultLanguageIsoCode
|
|
|
|
|
}), 'name');
|
2015-04-22 18:41:30 -03:00
|
|
|
};
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
// UX event handlers
|
|
|
|
|
$rootScope.$on('Local/ColorUpdated', function(event) {
|
|
|
|
|
self.updateColor();
|
2015-04-27 13:11:32 -03:00
|
|
|
$timeout(function() {
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
|
2015-05-14 10:39:22 -03:00
|
|
|
$rootScope.$on('Local/AliasUpdated', function(event) {
|
|
|
|
|
self.updateAlias();
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2015-06-29 22:40:39 -03:00
|
|
|
$rootScope.$on('Local/ProfileBound', function() {
|
|
|
|
|
storageService.getRemotePrefsStoredFlag(function(err, val) {
|
|
|
|
|
if (err || val) return;
|
|
|
|
|
self.updateRemotePreferences({
|
|
|
|
|
saveAll: true
|
|
|
|
|
}, function() {
|
|
|
|
|
$log.debug('Remote preferences saved')
|
|
|
|
|
storageService.setRemotePrefsStoredFlag(function() {});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2015-06-29 21:46:34 -03:00
|
|
|
|
|
|
|
|
$rootScope.$on('Local/NewFocusedWallet', function() {
|
|
|
|
|
self.setUxLanguage();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.$on('Local/LanguageSettingUpdated', function() {
|
|
|
|
|
self.setUxLanguage();
|
|
|
|
|
self.updateRemotePreferences({
|
|
|
|
|
saveAll: true
|
|
|
|
|
}, function() {
|
|
|
|
|
$log.debug('Remote preferences saved')
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2015-04-25 12:37:04 -03:00
|
|
|
$rootScope.$on('Local/UnitSettingUpdated', function(event) {
|
2015-03-06 12:00:10 -03:00
|
|
|
self.updateAll();
|
2015-04-21 12:20:54 -03:00
|
|
|
self.updateTxHistory();
|
2015-06-29 21:46:34 -03:00
|
|
|
self.updateRemotePreferences({
|
|
|
|
|
saveAll: true
|
|
|
|
|
}, function() {
|
|
|
|
|
$log.debug('Remote preferences saved')
|
|
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
|
2015-06-29 21:46:34 -03:00
|
|
|
$rootScope.$on('Local/EmailSettingUpdated', function(event, email, cb) {
|
|
|
|
|
self.updateRemotePreferences({
|
|
|
|
|
preferences: {
|
2015-07-14 17:29:56 -03:00
|
|
|
email: email || null
|
2015-06-29 21:46:34 -03:00
|
|
|
},
|
|
|
|
|
}, cb);
|
2015-05-19 14:10:47 -03:00
|
|
|
});
|
|
|
|
|
|
2015-04-25 12:37:04 -03:00
|
|
|
$rootScope.$on('Local/BWSUpdated', function(event) {
|
|
|
|
|
profileService.applyConfig();
|
2015-06-10 11:12:41 -03:00
|
|
|
storageService.setCleanAndScanAddresses(function() {});
|
|
|
|
|
});
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
$rootScope.$on('Local/WalletCompleted', function(event) {
|
|
|
|
|
self.setFocusedWallet();
|
|
|
|
|
go.walletHome();
|
|
|
|
|
});
|
|
|
|
|
|
2015-04-28 19:26:22 -03:00
|
|
|
self.debouncedUpdate = lodash.throttle(function() {
|
2015-06-29 21:46:34 -03:00
|
|
|
self.updateAll({
|
|
|
|
|
quiet: true
|
|
|
|
|
});
|
2015-04-28 19:26:22 -03:00
|
|
|
self.updateTxHistory();
|
2015-05-04 12:23:43 -03:00
|
|
|
}, 4000, {
|
|
|
|
|
leading: false,
|
|
|
|
|
trailing: true
|
|
|
|
|
});
|
2015-04-28 19:26:22 -03:00
|
|
|
|
|
|
|
|
|
2015-06-25 12:26:43 -03:00
|
|
|
$rootScope.$on('Local/Resume', function(event) {
|
|
|
|
|
$log.debug('### Resume event');
|
|
|
|
|
self.debouncedUpdate();
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.$on('Local/BackupDone', function(event) {
|
|
|
|
|
self.needsBackup = false;
|
2015-04-27 12:35:26 -03:00
|
|
|
storageService.setBackupFlag(self.walletId, function(err) {
|
|
|
|
|
if (err) $rootScope.$emit('Local/DeviceError', err)
|
|
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.$on('Local/NotAuthorized', function(event) {
|
|
|
|
|
self.notAuthorized = true;
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.$on('Local/BWSNotFound', function(event) {
|
2015-04-24 03:26:57 -03:00
|
|
|
self.clientError('Could not access Wallet Service: Not found');
|
2015-03-06 12:00:10 -03:00
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
|
2015-04-24 16:39:12 -03:00
|
|
|
$rootScope.$on('Local/DeviceError', function(event, err) {
|
|
|
|
|
self.deviceError(err);
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
$rootScope.$on('Local/ClientError', function(event, err) {
|
2015-04-13 11:57:58 -03:00
|
|
|
if (err.code && err.code === 'NOTAUTHORIZED') {
|
|
|
|
|
// Show not error, just redirect to home (where the recreate option is shown)
|
|
|
|
|
go.walletHome();
|
2015-04-13 14:58:07 -03:00
|
|
|
} else if (err && err.cors == 'rejected') {
|
|
|
|
|
$log.debug('CORS error:', err);
|
2015-05-29 11:46:33 -03:00
|
|
|
} else if (err.code === 'ETIMEDOUT' || err.code === 'CONNERROR') {
|
2015-04-13 16:24:25 -03:00
|
|
|
$log.debug('Time out:', err);
|
2015-04-13 11:57:58 -03:00
|
|
|
} else {
|
2015-04-24 10:10:01 -03:00
|
|
|
var msg = 'Error at Wallet Service: ';
|
|
|
|
|
if (err.message) msg = msg + err.message;
|
2015-04-24 14:46:09 -03:00
|
|
|
else if (err.error) msg = msg + err.error;
|
2015-05-19 14:10:47 -03:00
|
|
|
else msg = msg + (lodash.isObject(err) ? JSON.stringify(err) : err);
|
2015-04-24 10:10:01 -03:00
|
|
|
self.clientError(msg);
|
2015-04-13 11:57:58 -03:00
|
|
|
}
|
2015-03-06 12:00:10 -03:00
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.$on('Local/WalletImported', function(event, walletId) {
|
2015-05-04 15:47:04 -03:00
|
|
|
self.needsBackup = false;
|
2015-05-04 12:23:43 -03:00
|
|
|
storageService.setBackupFlag(walletId, function() {
|
2015-06-27 13:22:56 -03:00
|
|
|
addressService.expireAddress(walletId, function(err) {
|
2015-05-04 12:23:43 -03:00
|
|
|
self.startScan(walletId);
|
|
|
|
|
});
|
2015-04-18 07:23:11 -03:00
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
|
2015-04-15 14:03:38 -03:00
|
|
|
$rootScope.$on('NewIncomingTx', function() {
|
2015-07-06 10:40:40 -03:00
|
|
|
self.updateAll({
|
|
|
|
|
walletStatus: null,
|
|
|
|
|
untilItChanges: true,
|
|
|
|
|
triggerTxUpdate: true,
|
|
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
|
2015-05-29 12:39:17 -03:00
|
|
|
$rootScope.$on('NewOutgoingTx', function() {
|
2015-06-29 21:46:34 -03:00
|
|
|
self.updateAll({
|
|
|
|
|
walletStatus: null,
|
2015-07-06 11:12:40 -03:00
|
|
|
untilItChanges: true,
|
|
|
|
|
triggerTxUpdate: true,
|
2015-06-29 21:46:34 -03:00
|
|
|
});
|
2015-05-29 12:39:17 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
lodash.each(['NewTxProposal', 'TxProposalFinallyRejected', 'TxProposalRemoved',
|
2015-04-15 14:03:38 -03:00
|
|
|
'Local/NewTxProposal', 'Local/TxProposalAction', 'ScanFinished'
|
2015-03-06 12:00:10 -03:00
|
|
|
], function(eventName) {
|
2015-05-18 16:21:36 -03:00
|
|
|
$rootScope.$on(eventName, function(event, untilItChanges) {
|
2015-06-29 21:46:34 -03:00
|
|
|
self.updateAll({
|
|
|
|
|
walletStatus: null,
|
2015-07-06 10:40:40 -03:00
|
|
|
untilItChanges: untilItChanges,
|
|
|
|
|
triggerTxUpdate: true,
|
2015-06-29 21:46:34 -03:00
|
|
|
});
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy'], function(eventName) {
|
|
|
|
|
$rootScope.$on(eventName, function() {
|
|
|
|
|
var f = function() {
|
|
|
|
|
if (self.updatingStatus) {
|
|
|
|
|
return $timeout(f, 200);
|
|
|
|
|
};
|
|
|
|
|
self.updatePendingTxps();
|
|
|
|
|
};
|
|
|
|
|
f();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.$on('Local/NoWallets', function(event) {
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
self.hasProfile = true;
|
|
|
|
|
self.noFocusedWallet = true;
|
|
|
|
|
self.isComplete = null;
|
|
|
|
|
self.walletName = null;
|
2015-05-13 11:58:19 -03:00
|
|
|
go.path('import');
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.$on('Local/NewFocusedWallet', function() {
|
|
|
|
|
self.setFocusedWallet();
|
|
|
|
|
self.updateTxHistory();
|
2015-05-08 15:19:42 -03:00
|
|
|
go.walletHome();
|
2015-06-10 12:56:26 -03:00
|
|
|
storageService.getCleanAndScanAddresses(function(err, val) {
|
|
|
|
|
if (val) {
|
|
|
|
|
$log.debug('Clear last address cache and Scan');
|
2015-06-10 15:01:49 -03:00
|
|
|
lodash.each(lodash.keys(profileService.walletClients), function(walletId) {
|
2015-06-27 13:22:56 -03:00
|
|
|
addressService.expireAddress(walletId, function(err) {
|
2015-06-10 12:56:26 -03:00
|
|
|
self.startScan(walletId);
|
|
|
|
|
});
|
2015-06-10 15:01:49 -03:00
|
|
|
});
|
2015-06-10 12:56:26 -03:00
|
|
|
storageService.removeCleanAndScanAddresses(function() {});
|
|
|
|
|
}
|
|
|
|
|
});
|
2015-06-29 21:46:34 -03:00
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
});
|
|
|
|
|
|
2015-04-28 20:13:28 -03:00
|
|
|
$rootScope.$on('Local/SetTab', function(event, tab, reset) {
|
|
|
|
|
self.setTab(tab, reset);
|
2015-04-23 14:37:44 -03:00
|
|
|
});
|
|
|
|
|
|
2015-03-06 12:00:10 -03:00
|
|
|
$rootScope.$on('Local/NeedsPassword', function(event, isSetup, cb) {
|
|
|
|
|
self.askPassword = {
|
|
|
|
|
isSetup: isSetup,
|
2015-04-13 14:58:07 -03:00
|
|
|
callback: function(err, pass) {
|
2015-03-06 12:00:10 -03:00
|
|
|
self.askPassword = null;
|
|
|
|
|
return cb(err, pass);
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
lodash.each(['NewCopayer', 'CopayerUpdated'], function(eventName) {
|
|
|
|
|
$rootScope.$on(eventName, function() {
|
2015-04-29 12:16:28 -03:00
|
|
|
// Re try to open wallet (will triggers)
|
2015-03-06 12:00:10 -03:00
|
|
|
self.setFocusedWallet();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|