diff --git a/app-template/package.json b/app-template/package.json index 1b9235f8c..0d396c2af 100644 --- a/app-template/package.json +++ b/app-template/package.json @@ -42,7 +42,7 @@ "url": "https://github.com/bitpay/copay/issues" }, "dependencies": { - "bitcore-wallet-client": "4.0.0", + "bitcore-wallet-client": "4.1.0", "coveralls": "^2.11.9", "express": "^4.11.2", "fs": "0.0.2", diff --git a/chrome-app/manifest.json b/chrome-app/manifest.json index e6320e72a..7f7f2324b 100644 --- a/chrome-app/manifest.json +++ b/chrome-app/manifest.json @@ -1,6 +1,6 @@ - { + { "//":"PLEASE! Do not edit this file directly", - "//":" Modify it at app-template/", + "//":" Modify it at app-template/", "manifest_version": 2, "name": "BitPay", diff --git a/package.json b/package.json index 24776e4fc..ef792c82a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ - { + { "//":"PLEASE! Do not edit this file directly", - "//":" Modify it at app-template/", + "//":" Modify it at app-template/", "name": "bitpay", "description": "The BitPay Bitcoin Wallet", @@ -45,7 +45,7 @@ "url": "https://github.com/bitpay/copay/issues" }, "dependencies": { - "bitcore-wallet-client": "4.0.0", + "bitcore-wallet-client": "4.1.0", "coveralls": "^2.11.9", "express": "^4.11.2", "fs": "0.0.2", diff --git a/public/views/activity.html b/public/views/activity.html index d10d45479..bfbc44076 100644 --- a/public/views/activity.html +++ b/public/views/activity.html @@ -19,7 +19,7 @@
-
+
diff --git a/public/views/includes/walletActivity.html b/public/views/includes/walletActivity.html index 76931d556..33fe998ce 100644 --- a/public/views/includes/walletActivity.html +++ b/public/views/includes/walletActivity.html @@ -1,5 +1,15 @@ + +
+ Payment Sent +
+ {{x.amountStr}} +
+
+ + +
Payment Received
@@ -7,7 +17,6 @@
-
Proposal Deleted @@ -19,13 +28,13 @@
- + {{x.amountStr}} {{x.message}} - + Proposal Accepted @@ -33,10 +42,10 @@

+ {{ x.creatorName}}@ {{x.wallet.name}}

-
diff --git a/public/views/tab-home.html b/public/views/tab-home.html index a990d693a..d7e6688d0 100644 --- a/public/views/tab-home.html +++ b/public/views/tab-home.html @@ -5,9 +5,10 @@ -
-
+
+
Recent Activity +
diff --git a/src/js/controllers/activity.js b/src/js/controllers/activity.js index 897f1f21e..6205357c5 100644 --- a/src/js/controllers/activity.js +++ b/src/js/controllers/activity.js @@ -4,43 +4,19 @@ angular.module('copayApp.controllers').controller('activityController', function($rootScope, $timeout, $scope, $state, lodash, profileService, walletService, configService, txFormatService, $ionicModal, $log, platformInfo) { var self = this; - var setNotifications = function(notifications) { - var n = walletService.processNotifications(notifications); - - $scope.notifications = n; - $timeout(function() { - $scope.$apply(); - }, 1); - }; - - - $scope.init = function() { - $scope.wallets = profileService.getWallets(); - - var i = $scope.wallets.length, - j = 0; - var timeSpan = 60 * 60 * 24 * 7; - var notifications = []; - $scope.fetchingNotifications = true; - - lodash.each($scope.wallets, function(wallet) { - - walletService.getNotifications(wallet, { - timeSpan: timeSpan - }, function(err, n) { - if (err) { - console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO - return; - } - notifications.push(n); - if (++j == i) { - $scope.fetchingNotifications = false; - setNotifications(lodash.compact(lodash.flatten(notifications))); - }; - }); + profileService.getNotifications(50, function(err, n) { + if (err) { + console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO + return; + } + $scope.fetchingNotifications = false; + $scope.notifications = n; + $timeout(function() { + $scope.$apply(); + }, 1); }); } }); diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.js index b6886b5c2..1421b60f1 100644 --- a/src/js/controllers/tab-home.js +++ b/src/js/controllers/tab-home.js @@ -4,9 +4,7 @@ angular.module('copayApp.controllers').controller('tabHomeController', function($rootScope, $timeout, $scope, $state, lodash, profileService, walletService, configService, txFormatService, $ionicModal, $log, platformInfo, storageService) { var setNotifications = function(notifications) { - var n = walletService.processNotifications(notifications, 5); - $scope.notifications = n; - $scope.notificationsMore = notifications.length > 5 ? notifications.length - 5 : null; + $scope.notifications = notifications; $timeout(function() { $scope.$apply(); }, 1); @@ -16,41 +14,35 @@ angular.module('copayApp.controllers').controller('tabHomeController', $scope.wallets = profileService.getWallets(); if (lodash.isEmpty($scope.wallets)) return; - $timeout(function() { - var i = $scope.wallets.length; - var j = 0; - var timeSpan = 60 * 60 * 24 * 7; - var notifications = []; + var i = $scope.wallets.length; + var j = 0; + var timeSpan = 60 * 60 * 24 * 7; + var notifications = []; - $scope.fetchingNotifications = true; - - lodash.each($scope.wallets, function(wallet) { - - walletService.getStatus(wallet, {}, function(err, status) { - if (err) { - console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO - return; - } - wallet.status = status; - }); - - walletService.getNotifications(wallet, { - timeSpan: timeSpan - }, function(err, n) { - if (err) { - console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO - return; - } - notifications.push(n); - if (++j == i) { - $scope.fetchingNotifications = false; - setNotifications(lodash.compact(lodash.flatten(notifications))); - }; - }); + lodash.each($scope.wallets, function(wallet) { + walletService.getStatus(wallet, {}, function(err, status) { + if (err) { + console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO + return; + } + wallet.status = status; }); - $scope.$digest(); - }, 100); + + + }); + + $scope.fetchingNotifications = true; + profileService.getNotifications({ + limit: 3 + }, function(err, n) { + if (err) { + console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO + return; + } + $scope.fetchingNotifications = false; + setNotifications(n); + }) }; $scope.updateWallet = function(wallet) { @@ -61,9 +53,17 @@ angular.module('copayApp.controllers').controller('tabHomeController', return; } wallet.status = status; - $timeout(function() { - $scope.$apply(); - }, 1); + + profileService.getNotifications({ + limit: 3 + }, function(err, n) { + console.log('[tab-home.js.57]', n); //TODO + if (err) { + console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO + return; + } + setNotifications(n); + }) }); }; diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 1d6e5ffdb..0efb95b6a 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -1,6 +1,6 @@ 'use strict'; angular.module('copayApp.services') - .factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, sjcl, lodash, storageService, bwcService, configService, pushNotificationsService, gettext, gettextCatalog, bwcError, uxLanguage, bitcore, platformInfo, $ionicHistory) { + .factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, sjcl, lodash, storageService, bwcService, configService, pushNotificationsService, gettext, gettextCatalog, bwcError, uxLanguage, platformInfo, $ionicHistory, txFormatService, $state) { var isChromeApp = platformInfo.isChromeApp; @@ -119,6 +119,9 @@ angular.module('copayApp.services') if (wallet.completeHistory) wallet.completeHistory.isValid = false; + if (wallet.cachedActivity) + wallet.cachedActivity.isValid = false; + $rootScope.$emit('bwsEvent', wallet.id, n.type, n); }); @@ -130,7 +133,9 @@ angular.module('copayApp.services') }); }); - wallet.initialize({}, function(err) { + wallet.initialize({ + notificationIncludeOwn: true, + }, function(err) { if (err) { $log.error('Could not init notifications err:', err); return; @@ -426,8 +431,8 @@ angular.module('copayApp.services') // check if exist if (lodash.find(root.profile.credentials, { - 'walletId': walletData.walletId - })) { + 'walletId': walletData.walletId + })) { return cb(gettext('Cannot join the same wallet more that once')); } } catch (ex) { @@ -733,15 +738,155 @@ angular.module('copayApp.services') }); } else {} - return lodash.sortBy(ret, [function(x) { - return x.isComplete(); - }, 'createdOn']); + return lodash.sortBy(ret, [ + + function(x) { + return x.isComplete(); + }, 'createdOn' + ]); }; root.toggleHideBalanceFlag = function(walletId, cb) { root.wallet[walletId].balanceHidden = !root.wallet[walletId].balanceHidden; storageService.setHideBalanceFlag(walletId, root.wallet[walletId].balanceHidden.toString(), cb); - } + }; + + root.getNotifications = function(opts, cb) { + opts = opts || {}; + + var TIME_STAMP = 60 * 60 * 24 * 7; + var MAX = 100; + + var ignored = { + 'NewBlock': 1, + 'BalanceUpdated': 1, + 'NewOutgoingTxByThirdParty': 1, + 'NewAddress': 1, + 'TxProposalFinallyAccepted': 1, + 'TxProposalFinallyRejected': 1, + }; + + var w = root.getWallets(); + if (lodash.isEmpty(w)) return cb(); + + var l = w.length, + j = 0, + notifications = []; + + + function isActivityCached(wallet) { + return wallet.cachedActivity && wallet.cachedActivity.isValid; + }; + + + function getNotifications(wallet, cb2) { + if (isActivityCached(wallet) && !opts.force) return cb2(); + + wallet.getNotifications({ + timeSpan: TIME_STAMP, + includeOwn: true, + }, function(err, n) { + if (err) return cb2(err); + + wallet.cachedActivity = { + n: n.slice(-MAX), + isValid: true, + }; + + return cb2(); + }); + }; + + function process(notifications) { + if (!notifications) return []; + + var shown = lodash.sortBy(notifications, 'createdOn').reverse(); + + shown = shown.splice(0, opts.limit || MAX); + + lodash.each(shown, function(x) { + x.txpId = x.data ? x.data.txProposalId : null; + x.txid = x.data ? x.data.txid : null; + x.types = [x.type]; + + if (x.data && x.data.amount) + x.amountStr = txFormatService.formatAmountStr(x.data.amount); + + x.action = function() { + // TODO? + $state.go('wallet.details', { + walletId: x.walletId, + txpId: x.txpId, + txid: x.txid, + }); + }; + }); + + // condense + var finale = [], + prev; + + + lodash.each(shown, function(x) { + if (prev && prev.walletId === x.walletId && prev.txpId && prev.txpId === x.txpId && prev.creatorId && prev.creatorId === x.creatorId) { + prev.types.push(x.type); + prev.data = lodash.assign(prev.data, x.data); + prev.txid = prev.txid || x.txid; + prev.amountStr = prev.amountStr || x.amountStr; + prev.creatorName = prev.creatorName || x.creatorName; + } else { + finale.push(x); + prev = x; + } + }); + + // messages... + + var u = bwcService.getUtils(); + lodash.each(finale, function(x) { + if (x.data && x.data.message && x.wallet && x.wallet.credentials.sharedEncryptingKey) { + // TODO TODO TODO => BWC + x.message = u.decryptMessage(x.data.message, x.wallet.credentials.sharedEncryptingKey); + } + }); + + return finale; + }; + + lodash.each(w, function(wallet) { + getNotifications(wallet, function(err) { + j++; + if (err) { + $log.warn('Error updating notifications:' + err); + } else { + var n = lodash.filter(wallet.cachedActivity.n, function(x) { + return !ignored[x.type]; + }); + + var idToName = {}; + if (wallet.cachedStatus) { + lodash.each(wallet.cachedStatus.wallet.copayers, function(c) { + idToName[c.id] = c.name; + }); + } + + lodash.each(n, function(x) { + x.wallet = wallet; + if (x.creatorId && wallet.cachedStatus) { + x.creatorName = idToName[x.creatorId]; + }; + }); + + notifications.push(n); + } + if (j == l) { + notifications = lodash.sortBy(notifications, 'createdOn'); + notifications = lodash.compact(lodash.flatten(notifications)).slice(0,MAX); + return cb(null, process(notifications)); + }; + }); + }); + }; return root; }); diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index bdfe1a291..fd5a5bfa2 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -976,33 +976,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; - root.getNotifications = function(wallet, opts, cb) { - - wallet.getNotifications(opts, function(err, notifications) { - if (err) return cb(err); - - notifications = lodash.filter(notifications, function(x) { - return x.type != 'NewBlock' && x.type != 'BalanceUpdated' && x.type != 'NewOutgoingTxByThirdParty'; - }); - - var idToName = {}; - if (wallet.cachedStatus) { - lodash.each(wallet.cachedStatus.wallet.copayers, function(c) { - idToName[c.id] = c.name; - }); - } - - lodash.each(notifications, function(x) { - x.wallet = wallet; - if (x.creatorId && wallet.cachedStatus) { - x.creatorName = idToName[x.creatorId]; - }; - }); - - return cb(null, notifications); - }); - }; - root.getEncodedWalletInfo = function(wallet, cb) { var derivationPath = wallet.credentials.getBaseAddressDerivationPath(); @@ -1036,64 +1009,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; - root.processNotifications = function(notifications, limit) { - if (!notifications) return []; - - var shown = lodash.sortBy(notifications, 'createdOn').reverse(); - - if (limit) - shown = shown.splice(0, limit); - - lodash.each(shown, function(x) { - x.txpId = x.data ? x.data.txProposalId : null; - x.txid = x.data ? x.data.txid : null; - x.types = [x.type]; - - if (x.data && x.data.amount) - x.amountStr = txFormatService.formatAmountStr(x.data.amount); - - x.action = function() { - // TODO? - $state.go('wallet.details', { - walletId: x.walletId, - txpId: x.txpId, - txid: x.txid, - }); - }; - }); - - // condense - var finale = [], - prev; - - - lodash.each(shown, function(x) { - if (prev && prev.walletId === x.walletId && prev.txpId && prev.txpId === x.txpId && prev.creatorId && prev.creatorId === x.creatorId) { - prev.types.push(x.type); - prev.data = lodash.assign(prev.data, x.data); - prev.txid = prev.txid || x.txid; - prev.amountStr = prev.amountStr || x.amountStr; - prev.creatorName = prev.creatorName || x.creatorName; - } else { - finale.push(x); - prev = x; - } - }); - - // messages... - - var u = bwcService.getUtils(); - lodash.each(finale, function(x) { - if (x.data && x.data.message && x.wallet && x.wallet.credentials.sharedEncryptingKey) { - // TODO TODO TODO => BWC - x.message = u.decryptMessage(x.data.message, x.wallet.credentials.sharedEncryptingKey); - } - }); - - return finale; - }; - - root.setTouchId = function(wallet, enabled, cb) { fingerprintService.check(wallet, function(err) { if (err) return cb(err); {