Merge pull request #400 from matiu/feature/optimizations

Feature/optimizations
This commit is contained in:
Manuel Aráoz 2014-05-16 18:57:55 -03:00
commit db0a432bc8
9 changed files with 183 additions and 133 deletions

View File

@ -22,7 +22,7 @@
<div class="large-9 medium-9 columns text-center p10t" ng-show="$root.wallet">
<div class="large-4 medium-4 columns line-dashed-v">
<a href="#/addresses" class="has-tip" tooltip-placement="bottom" tooltip="{{$root.wallet.id}}">
<strong><span>{{$root.getWalletDisplay()}}</span></strong>
<strong><span>{{$root.wallet.getName()}}</span></strong>
</a>
<a class="button radius small-icon" title="Manual Refresh"
ng-disabled="$root.loading"
@ -32,14 +32,14 @@
</div>
<div class="large-4 medium-4 columns line-dashed-v">
Balance:
<span ng-if="$root.loading">...</span>
<span ng-if="!$root.loading">{{totalBalance || 0}}</span>
<span ng-if="$root.updatingBalance">...</span>
<span ng-if="!$root.updatingBalance">{{totalBalance || 0}}</span>
<i class="fi-bitcoin"></i><br>
</div>
<div class="large-4 medium-4 columns">
Available to Spend:
<span ng-if="$root.loading">...</span>
<span ng-if="!$root.loading">{{availableBalance || 0}}</span>
<span ng-if="$root.updatingBalance">...</span>
<span ng-if="!$root.updatingBalance">{{availableBalance || 0}}</span>
<i class="fi-bitcoin"></i>
</div>
@ -101,7 +101,7 @@
</div>
</div>
<div class="large-3 columns hide-for-medium hide-for-small" ng-show="$root.wallet">
<h5 class="m0">{{$root.getWalletDisplay()}}</h5>
<h5 class="m0">{{$root.wallet.getName()}}</h5>
<p class="text-gray">{{$root.wallet.requiredCopayers}}-of-{{$root.wallet.totalCopayers}} wallet</p>
</div>
</div>
@ -129,7 +129,7 @@
<div class="row p10t" ng-show="$root.wallet">
<div class="large-3 medium-3 small-3 columns">
<div>
<strong>{{$root.getWalletDisplay()}}</strong>
<strong>{{$root.wallet.getName()}}</strong>
</div>
<div class="size-12 m10t">
{{$root.wallet.requiredCopayers}}-of-{{$root.wallet.totalCopayers}} wallet
@ -146,7 +146,7 @@
avatar peer="{{c}}"
autoplay
ng-class="($root.wallet.getOnlinePeerIDs().indexOf(c.peerId) != -1) ? 'online' : 'offline'"
ng-src="{{$root.getVideoURL(c.peerId)}}"
ng-src="{{getVideoURL(c.peerId)}}"
></video>
<img ng-if="!$root.videoInfo[c.peerId]"
avatar peer="{{c}}"
@ -324,8 +324,8 @@
<span>{{addrInfo.address.toString()}}</span>
<span ng-if="addrInfo.isChange">(change)</span>
<span class="right">
<span ng-if="$root.loading">...</span>
<span ng-if="!$root.loading">{{balanceByAddr[addrInfo.address.toString()] || 0}}</span>
<span ng-if="$root.updatingBalance">...</span>
<span ng-if="!$root.updatingBalance">{{balanceByAddr[addrInfo.address.toString()] || 0}}</span>
<i class="fi-bitcoin"></i>
</span>
</a>
@ -334,8 +334,8 @@
<qrcode size="160" data="{{selectedAddr}}"></qrcode>
<p class="m10t">
<strong>
<span ng-if="$root.loading">...</span>
<span ng-if="!$root.loading">{{balanceByAddr[selectedAddr] || 0}}</span>
<span ng-if="$root.updatingBalance">...</span>
<span ng-if="!$root.updatingBalance">{{balanceByAddr[selectedAddr] || 0}}</span>
<i class="fi-bitcoin"></i>
</strong>
</p>
@ -405,16 +405,15 @@
</div>
<div class="row m15">
<div class="large-4 columns" ng-show="!tx.sentTs" style="padding-left: 5px;">
<div class="large-5 columns" ng-show="!tx.sentTs" style="padding-left: 5px;">
<div ng-show="!tx.signedByUs && !tx.rejectedByUs && !tx.finallyRejected && tx.missingSignatures">
<button class="secondary radius m10r" ng-click="sign(tx.ntxid)" ng-disabled="loading">
<button class="secondary radius m10r" ng-click="sign(tx.ntxid)" ng-disabled="loading" loading="Signing">
<i class="fi-check"></i> Sign
</button>
<button class="warning radius" ng-click="reject(tx.ntxid)" ng-disabled="loading">
<button class="warning radius" ng-click="reject(tx.ntxid)" ng-disabled="loading" loading="Rejecting">
<i class="fi-x" ></i> Reject
</button>
</div>
<span ng-show="!tx.missingSignatures && !tx.sentTs">
<button class="primary radius" ng-click="send(tx.ntxid)" ng-disabled="loading" loading="Broadcasting"> <i class=".fi-upload-cloud"></i>
Broadcast Transaction
@ -422,7 +421,7 @@
</span>
</div>
<div class="large-8 columns text-right">
<div class="large-7 columns text-right">
<span ng-show="tx.finallyRejected" class="text-warning">
Transaction finally rejected
</span>

View File

@ -2,15 +2,17 @@
angular.module('copay.addresses').controller('AddressesController',
function($scope, $rootScope, controllerUtils) {
var w = $rootScope.wallet;
$scope.loading = false;
var w = $rootScope.wallet;
$scope.newAddr = function() {
$scope.loading = true;
w.generateAddress();
controllerUtils.updateBalance(function() {
$scope.loading = false;
$scope.loading=true;
w.generateAddress(null, function() {
setTimeout(function() {
controllerUtils.setSocketHandlers();
controllerUtils.updateAddressList();
$scope.loading=false;
$rootScope.$digest();
},1);
});
};

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copay.footer').controller('FooterController', function($scope, $http) {
angular.module('copay.footer').controller('FooterController', function($rootScope, $sce, $scope, $http) {
if (config.themes && Array.isArray(config.themes) && config.themes[0]) {
$scope.themes = config.themes;
@ -15,4 +15,20 @@ angular.module('copay.footer').controller('FooterController', function($scope, $
$scope.theme = 'css/tpl-' + name + '.css';
};
$scope.version = copay.version;
$scope.getVideoURL = function(copayer) {
var vi = $rootScope.videoInfo[copayer]
if (!vi) return;
if ($rootScope.wallet.getOnlinePeerIDs().indexOf(copayer) === -1) {
// peer disconnected, remove his video
delete $rootScope.videoInfo[copayer]
return;
}
var encoded = vi.url;
var url = decodeURI(encoded);
var trusted = $sce.trustAsResourceUrl(url);
return trusted;
};
});

View File

@ -7,6 +7,8 @@ angular.module('copay.signin').controller('SigninController',
return v1 > v2 ? 1 : ( v1 < v2 ) ? -1 : 0;
};
$rootScope.videoInfo = {};
$scope.loading = $scope.failure = false;
$scope.wallets = walletFactory.getWallets().sort(cmp);
$scope.selectedWalletId = $scope.wallets.length ? $scope.wallets[0].id : null;
@ -20,6 +22,8 @@ angular.module('copay.signin').controller('SigninController',
$rootScope.walletName = form.walletName.$modelValue;
$rootScope.walletPassword = form.createPassword.$modelValue;
$location.path('setup');
};
@ -31,7 +35,10 @@ angular.module('copay.signin').controller('SigninController',
$scope.loading = true;
var password = form.openPassword.$modelValue;
console.log('## Obtaining passphrase...');
Passphrase.getBase64Async(password, function(passphrase){
console.log('## Done.');
var w = walletFactory.open($scope.selectedWalletId, { passphrase: passphrase});
if (!w) {
$scope.loading = $scope.failure = false;
@ -39,8 +46,8 @@ angular.module('copay.signin').controller('SigninController',
$rootScope.$digest();
return;
}
installStartupHandlers(w);
controllerUtils.startNetwork(w);
listenErrors(w);
});
};
@ -67,16 +74,19 @@ angular.module('copay.signin').controller('SigninController',
controllerUtils.onErrorDigest();
} else {
controllerUtils.startNetwork(w);
listenErrors(w);
installStartupHandlers(w);
}
});
});
};
function listenErrors(wallet) {
function installStartupHandlers(wallet) {
wallet.network.on('error', function(err) {
$scope.failure = true;
});
wallet.on('ready', function() {
$scope.loading = false;
});
}
});

View File

@ -6,7 +6,13 @@ angular.module('copay.transactions').controller('TransactionsController',
$scope.title = 'Transactions';
$scope.loading = false;
$scope.send = function (ntxid) {
$scope.update = function () {
$scope.loading = false;
controllerUtils.updateTxs();
$rootScope.$digest();
};
$scope.send = function (ntxid,cb) {
$scope.loading = true;
$rootScope.txAlertCount = 0;
var w = $rootScope.wallet;
@ -16,34 +22,32 @@ angular.module('copay.transactions').controller('TransactionsController',
? {type:'success', message: 'Transaction broadcasted. txid: ' + txid}
: {type:'error', message: 'There was an error sending the Transaction'}
;
controllerUtils.updateTxs();
$scope.loading = false;
$rootScope.$digest();
if (cb) return cb();
else $scope.update();
});
};
$scope.sign = function (ntxid) {
$scope.loading = true;
var w = $rootScope.wallet;
var ret = w.sign(ntxid);
if (!ret) {
$rootScope.flashMessage = {type:'error', message: 'There was an error signing the Transaction'};
controllerUtils.updateTxs();
$scope.loading = false;
$rootScope.$digest();
return;
}
var p = w.txProposals.getTxProposal(ntxid);
if (p.builder.isFullySigned()) {
$scope.send(ntxid);
controllerUtils.updateTxs();
}
else {
controllerUtils.updateTxs();
$scope.loading = false;
$rootScope.$digest();
}
w.sign(ntxid, function(ret){
if (!ret) {
$rootScope.flashMessage = {
type:'error',
message: 'There was an error signing the Transaction',
};
$scope.update();
}
else {
var p = w.txProposals.getTxProposal(ntxid);
if (p.builder.isFullySigned()) {
$scope.send(ntxid, function() {
$scope.update();
});
}
else $scope.update();
}
});
};
$scope.getTransactions = function() {

View File

@ -23,7 +23,7 @@ angular.module('copay.directives')
};
}
])
.directive('notification', ['$rootScope',
.directive('notification', ['$rootScope',
function($rootScope) {
return {
restrict: 'A',
@ -82,13 +82,14 @@ angular.module('copay.directives')
.directive('loading', function() {
return {
restrict: 'A',
link: function(scope, element, attr) {
link: function($scope, element, attr) {
var a = element.html();
var text = attr.loading;
scope.$watch('loading', function(val) {
if (val) {
element.on('click', function() {
element.html('<i class="size-21 fi-bitcoin-circle icon-rotate spinner"></i> ' + text + '...');
} else {
});
$scope.$watch('loading', function(val) {
if (!val) {
element.html(a);
}
});
@ -104,14 +105,14 @@ angular.module('copay.directives')
});
}
}
}).directive('avatar', function($rootScope) {
}).directive('avatar', function($rootScope, controllerUtils) {
return {
link: function(scope, element, attrs) {
var peer = JSON.parse(attrs.peer)
var peerId = peer.peerId;
var nick = peer.nick;
element.addClass('video-small');
var muted = $rootScope.getVideoMutedStatus(peerId);
var muted = controllerUtils.getVideoMutedStatus(peerId);
if (muted) {
element.attr("muted", true);
}

View File

@ -79,7 +79,7 @@ Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) {
recipients = null;
this.sendPublicKeyRing(recipients);
}
this.emit('refresh', this.publicKeyRing);
this.emit('publicKeyRingUpdated');
this.store();
};
@ -222,11 +222,15 @@ Wallet.prototype.netStart = function() {
if (this.publicKeyRing.isComplete()) {
this._lockIncomming();
}
net.start(startOpts, function() {
self.connectToAll();
self.emit('ready', net.getPeer());
self.emit('refresh');
setTimeout(function(){
console.log('[EMIT publicKeyRingUpdated:]'); //TODO
self.emit('publicKeyRingUpdated');
console.log('[CONNECT:]'); //TODO
self.connectToAll();
self.emit('txProposalsUpdated');
},10);
});
};
@ -346,11 +350,20 @@ Wallet.prototype.sendPublicKeyRing = function(recipients) {
});
};
Wallet.prototype.getName = function() {
return this.name || this.id;
};
Wallet.prototype.generateAddress = function(isChange) {
var addr = this.publicKeyRing.generateAddress(isChange);
Wallet.prototype._doGenerateAddress = function(isChange) {
return this.publicKeyRing.generateAddress(isChange);
};
Wallet.prototype.generateAddress = function(isChange, cb) {
var addr = this._doGenerateAddress(isChange);
this.sendPublicKeyRing();
this.store();
if (cb) return cb(addr);
return addr;
};
@ -383,27 +396,30 @@ Wallet.prototype.reject = function(ntxid) {
};
Wallet.prototype.sign = function(ntxid) {
Wallet.prototype.sign = function(ntxid, cb) {
var self = this;
var myId = this.getMyCopayerId();
var txp = self.txProposals.txps[ntxid];
if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) return;
setTimeout(function() {
var myId = self.getMyCopayerId();
var txp = self.txProposals.txps[ntxid];
if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) return;
var pkr = self.publicKeyRing;
var keys = self.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex);
var pkr = self.publicKeyRing;
var keys = self.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex);
var b = txp.builder;
var before = b.signaturesAdded;
b.sign(keys);
var b = txp.builder;
var before = b.signaturesAdded;
b.sign(keys);
if (b.signaturesAdded > before) {
txp.signedBy[myId] = Date.now();
this.sendTxProposals(null, ntxid);
this.store();
this.emit('txProposalsUpdated');
return true;
}
return false;
var ret = false;
if (b.signaturesAdded > before) {
txp.signedBy[myId] = Date.now();
self.sendTxProposals(null, ntxid);
self.store();
self.emit('txProposalsUpdated');
ret = true;
}
if (cb) return cb(ret);
},10);
};
Wallet.prototype.sendTx = function(ntxid, cb) {
@ -423,9 +439,9 @@ Wallet.prototype.sendTx = function(ntxid, cb) {
self.log('BITCOND txid:', txid); //TODO
if (txid) {
self.txProposals.setSent(ntxid, txid);
self.sendTxProposals(null, ntxid);
self.store();
}
self.sendTxProposals(null, ntxid);
self.store();
return cb(txid);
});
};
@ -536,7 +552,7 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, opts, cb) {
self.getUnspent(function(safeUnspent) {
var ntxid = self.createTxSync(toAddress, amountSatStr, safeUnspent, opts);
if (ntxid) {
self.sendPublicKeyRing(); // For the new change Address
self.sendPublicKeyRing();
self.sendTxProposals(null, ntxid);
self.store();
self.emit('txProposalsUpdated');
@ -558,7 +574,7 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) {
if (!opts.remainderOut) {
opts.remainderOut = {
address: this.generateAddress(true).toString()
address: this._doGenerateAddress(true).toString()
};
}

View File

@ -3,26 +3,8 @@
angular.module('copay.controllerUtils')
.factory('controllerUtils', function($rootScope, $sce, $location, Socket, video) {
var root = {};
$rootScope.videoInfo = {};
$rootScope.loading = false;
$rootScope.getVideoURL = function(copayer) {
var vi = $rootScope.videoInfo[copayer]
if (!vi) return;
if ($rootScope.wallet.getOnlinePeerIDs().indexOf(copayer) === -1) {
// peer disconnected, remove his video
delete $rootScope.videoInfo[copayer]
return;
}
var encoded = vi.url;
var url = decodeURI(encoded);
var trusted = $sce.trustAsResourceUrl(url);
return trusted;
};
$rootScope.getVideoMutedStatus = function(copayer) {
root.getVideoMutedStatus = function(copayer) {
var vi = $rootScope.videoInfo[copayer]
if (!vi) {
return;
@ -30,17 +12,17 @@ angular.module('copay.controllerUtils')
return vi.muted;
};
$rootScope.getWalletDisplay = function() {
var w = $rootScope.wallet;
return w && (w.name || w.id);
};
root.logout = function() {
$rootScope.wallet = null;
delete $rootScope['wallet'];
$rootScope.totalBalance = 0;
video.close();
$rootScope.videoInfo = {};
// Clear rootScope
for (var i in $rootScope) {
if (i.charAt(0) != '$') {
delete $rootScope[i];
}
}
$location.path('signin');
};
@ -73,18 +55,21 @@ angular.module('copay.controllerUtils')
};
});
w.on('ready', function(myPeerID) {
video.setOwnPeer(myPeerID, w, handlePeerVideo);
$rootScope.wallet = w;
$location.path('addresses');
$rootScope.$digest();
video.setOwnPeer(myPeerID, w, handlePeerVideo);
});
w.on('refresh', function() {
root.updateBalance();
w.on('publicKeyRingUpdated', function() {
root.setSocketHandlers();
root.updateAddressList();
$rootScope.$digest();
});
w.on('txProposalsUpdated', function() {
root.updateTxs();
root.updateBalance();
root.updateBalance(function(){
$rootScope.$digest();
});
});
w.on('openError', root.onErrorDigest);
w.on('connect', function(peerID) {
@ -100,25 +85,28 @@ angular.module('copay.controllerUtils')
w.netStart();
};
root.updateBalance = function(cb) {
console.log('Updating balance...');
$rootScope.balanceByAddr = {};
root.updateAddressList = function() {
var w = $rootScope.wallet;
$rootScope.addrInfos = w.getAddressesInfo();
};
root.updateBalance = function(cb) {
console.log('Updating balance...');
root.updateAddressList();
var w = $rootScope.wallet;
if ($rootScope.addrInfos.length === 0) return;
$rootScope.loading = true;
$rootScope.balanceByAddr = {};
$rootScope.updatingBalance = true;
w.getBalance(function(balance, balanceByAddr, safeBalance) {
$rootScope.loading = false;
$rootScope.totalBalance = balance;
$rootScope.balanceByAddr = balanceByAddr;
$rootScope.selectedAddr = $rootScope.addrInfos[0].address.toString();
$rootScope.availableBalance = safeBalance;
$rootScope.$digest();
$rootScope.updatingBalance = false;
console.log('Done updating balance.'); //TODO
if (cb) cb();
});
root.setSocketHandlers();
};
root.updateTxs = function() {
@ -163,23 +151,30 @@ angular.module('copay.controllerUtils')
$rootScope.pendingTxCount = pending;
w.removeListener('txProposalsUpdated',root.updateTxs)
w.once('txProposalsUpdated',root.updateTxs);
$rootScope.loading = false;
};
root.setSocketHandlers = function() {
// TODO: optimize this?
Socket.removeAllListeners();
if (!$rootScope.wallet) return;
var currentAddrs= Socket.getListeners();
var addrs = $rootScope.wallet.getAddressesStr();
for (var i = 0; i < addrs.length; i++) {
console.log('### SUBSCRIBE TO', addrs[i]);
Socket.emit('subscribe', addrs[i]);
var newAddrs=[];
for(var i in addrs){
var a=addrs[i];
if (!currentAddrs[a])
newAddrs.push(a);
}
addrs.forEach(function(addr) {
for (var i = 0; i < newAddrs.length; i++) {
console.log('### SUBSCRIBE TO', newAddrs[i]);
Socket.emit('subscribe', newAddrs[i]);
}
newAddrs.forEach(function(addr) {
Socket.on(addr, function(txid) {
console.log('Received!', txid);
root.updateBalance();
root.updateBalance(function(){
$rootScope.$digest();
});
});
});
};

View File

@ -19,7 +19,6 @@ angular.module('copay.socket').factory('Socket',
};
socket.on(event, wrappedCallback);
if (event !== 'connect') {
listeners.push({
event: event,
@ -27,6 +26,14 @@ angular.module('copay.socket').factory('Socket',
});
}
},
getListeners: function() {
var ret = {};
var addrList = listeners.map(function(i) {return i.event;});
for (var i in addrList) {
ret[addrList[i]] = 1;
}
return ret;
},
emit: function(event, data, callback) {
socket.emit(event, data, function() {
var args = arguments;