From 94a2b8237a7015214e7c2875cebb7a3218deb6c8 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Fri, 13 Jun 2014 11:54:59 -0300 Subject: [PATCH 1/2] Random fix: hide paginator when it has only one page --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index caf3c0eb1..f96b27ae7 100644 --- a/index.html +++ b/index.html @@ -529,7 +529,7 @@

No pending transactions proposals.

No transactions proposals yet.

- +

Last transactions

From 6ab77e8711f6384c761ec7daba7d39cfc1bf9575 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Fri, 13 Jun 2014 17:24:44 -0300 Subject: [PATCH 2/2] Add user notifications on transaction signed and rejected events --- js/models/core/TxProposals.js | 30 ++++++++++++++++++------------ js/models/core/Wallet.js | 5 ++++- js/services/controllerUtils.js | 12 ++++++++++++ test/test.TxProposals.js | 26 +++++++++++++++++++------- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/js/models/core/TxProposals.js b/js/models/core/TxProposals.js index 4bc4f2fa9..c9a5bcf3c 100644 --- a/js/models/core/TxProposals.js +++ b/js/models/core/TxProposals.js @@ -97,11 +97,13 @@ TxProposals.prototype._startMerge = function(myTxps, theirTxps) { fromTheirs = 0, merged = 0; var toMerge = {}, - ready = {}; + ready = {}, + events = []; for (var hash in theirTxps) { if (!myTxps[hash]) { ready[hash] = theirTxps[hash]; // only in theirs; + events.push({type: 'new', cid: theirTxps[hash].creator, tx: hash}); fromTheirs++; } else { toMerge[hash] = theirTxps[hash]; // need Merging @@ -124,6 +126,7 @@ TxProposals.prototype._startMerge = function(myTxps, theirTxps) { }, ready: ready, toMerge: toMerge, + events: events }; }; @@ -132,6 +135,7 @@ TxProposals.prototype._mergeMetadata = function(myTxps, theirTxps, mergeInfo) { var toMerge = mergeInfo.toMerge; var hasChanged = 0; + var events = []; Object.keys(toMerge).forEach(function(hash) { var v0 = myTxps[hash]; @@ -140,32 +144,36 @@ TxProposals.prototype._mergeMetadata = function(myTxps, theirTxps, mergeInfo) { Object.keys(v1.seenBy).forEach(function(k) { if (!v0.seenBy[k]) { v0.seenBy[k] = v1.seenBy[k]; - hasChanged++; + events.push({type: 'seen', cId: k, txId: hash}); } }); Object.keys(v1.signedBy).forEach(function(k) { if (!v0.signedBy[k]) { v0.signedBy[k] = v1.signedBy[k]; - hasChanged++; + events.push({type: 'signed', cId: k, txId: hash}); } }); Object.keys(v1.rejectedBy).forEach(function(k) { if (!v0.rejectedBy[k]) { v0.rejectedBy[k] = v1.rejectedBy[k]; - hasChanged++; + events.push({type: 'rejected', cId: k, txId: hash}); } }); if (!v0.sentTxid && v1.sentTxid) { v0.sentTs = v1.sentTs; v0.sentTxid = v1.sentTxid; - hasChanged++; + events.push({type: 'broadcast', txId: hash}); } }); - return hasChanged; + + return { + events: events.concat(mergeInfo.events), + hasChanged: events.length + }; }; @@ -255,21 +263,19 @@ TxProposals.prototype.merge = function(t) { if (this.network.name !== t.network.name) throw new Error('network mismatch in:', t); - var res = []; - var hasChanged = 0; - var myTxps = this.txps; var theirTxps = t.txps; var mergeInfo = this._startMerge(myTxps, theirTxps); - hasChanged += this._mergeMetadata(myTxps, theirTxps, mergeInfo); - hasChanged += this._mergeBuilder(myTxps, theirTxps, mergeInfo); + var result = this._mergeMetadata(myTxps, theirTxps, mergeInfo); + result.hasChanged += this._mergeBuilder(myTxps, theirTxps, mergeInfo); Object.keys(mergeInfo.toMerge).forEach(function(hash) { mergeInfo.ready[hash] = myTxps[hash]; }); - mergeInfo.stats.hasChanged = hasChanged; + mergeInfo.stats.hasChanged = result.hasChanged; + mergeInfo.stats.events = result.events; this.txps = mergeInfo.ready; return mergeInfo.stats; diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 4dfd7708d..2bb53df60 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -117,7 +117,7 @@ Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) { var inTxp = copay.TxProposals.fromObj(data.txProposals); var ids = inTxp.getNtxids(); - if (ids.lenght > 1) { + if (ids.length > 1) { this.emit('badMessage', senderId); this.log('Received BAD TxProposal messsage FROM:', senderId); //TODO return; @@ -135,6 +135,9 @@ Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) { this.emit('txProposalsUpdated'); this.store(); } + for (var i = 0; i < mergeInfo.events.length; i++) { + this.emit('txProposalEvent', mergeInfo.events[i]); + } }; Wallet.prototype._handleData = function(senderId, data, isInbound) { diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index a512d5fd6..5a7c6817d 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -122,6 +122,18 @@ angular.module('copayApp.services') }); }, 3000); }); + w.on('txProposalEvent', function(e){ + switch (e.type) { + case 'signed': + var user = w.publicKeyRing.nicknameForCopayer(e.cId); + $notification.info('Transaction Update', 'A transaction was signed by ' + user); + break; + case 'rejected': + var user = w.publicKeyRing.nicknameForCopayer(e.cId); + $notification.info('Transaction Update', 'A transaction was rejected by ' + user); + break; + } + }); w.on('connectionError', function(msg) { root.onErrorDigest(null, msg); }); diff --git a/test/test.TxProposals.js b/test/test.TxProposals.js index 9ae69412c..59beb4822 100644 --- a/test/test.TxProposals.js +++ b/test/test.TxProposals.js @@ -215,7 +215,9 @@ describe('TxProposals model', function() { (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true); - w.merge(w); + var info = w.merge(w); + info.events.length.should.equal(0); + Object.keys(w.txps).length.should.equal(1); tx.isComplete().should.equal(false); @@ -287,7 +289,10 @@ describe('TxProposals model', function() { (w2.txps[k].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv.id] - ts > 0).should.equal(true); - w.merge(w2); + var info = w.merge(w2); + info.events.length.should.equal(1); + info.events[0].type.should.equal('signed'); + Object.keys(w.txps).length.should.equal(1); var tx = w.txps[k].builder.build(); @@ -392,8 +397,9 @@ describe('TxProposals model', function() { (w2.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true); - w.merge(w2); - Object.keys(w.txps).length.should.equal(1); + var info = w.merge(w2); + info.events.length.should.equal(1); + info.events[0].type.should.equal('signed'); tx = w.txps[ntxid].builder.build(); tx.isComplete().should.equal(false); @@ -421,7 +427,9 @@ describe('TxProposals model', function() { (w3.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true); (w3.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true); - w.merge(w3); + var info = w.merge(w3); + info.events.length.should.equal(0); + Object.keys(w.txps).length.should.equal(1); (w.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true); @@ -510,7 +518,9 @@ describe('TxProposals model', function() { (w3.txps[k].signedBy[priv3.id] - ts > 0).should.equal(true); (w3.txps[k].seenBy[priv3.id] - ts > 0).should.equal(true); - w.merge(w2); + var info = w.merge(w2); + info.events.length.should.equal(0); + Object.keys(w.txps).length.should.equal(1); var tx = w.txps[k].builder.build(); tx.isComplete().should.equal(false); @@ -521,7 +531,9 @@ describe('TxProposals model', function() { (w.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true); - w.merge(w3); + var info = w.merge(w3); + info.events.length.should.equal(0); + var tx = w.txps[k].builder.build(); tx.isComplete().should.equal(true); tx.countInputMissingSignatures(0).should.equal(0);