Merge pull request #5070 from JDonadio/feat/address-view

Feat/address view
This commit is contained in:
Gustavo Maximiliano Cortez 2016-11-22 09:34:46 -03:00 committed by GitHub
commit 3b6926e463
15 changed files with 470 additions and 118 deletions

View file

@ -0,0 +1,199 @@
'use strict';
angular.module('copayApp.controllers').controller('addressesController', function($scope, $stateParams, $state, $timeout, $ionicHistory, $ionicPopover, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, platformInfo) {
var UNUSED_ADDRESS_LIMIT = 5;
var BALANCE_ADDRESS_LIMIT = 5;
var MENU_ITEM_HEIGHT = 55;
var config;
var unitName;
var unitToSatoshi;
var satToUnit;
var unitDecimals;
var withBalance;
$scope.showInfo = false;
$scope.showMore = false;
$scope.allAddressesView = false;
$scope.isCordova = platformInfo.isCordova;
$scope.wallet = profileService.getWallet($stateParams.walletId);
function init() {
ongoingProcess.set('gettingAddresses', true);
walletService.getMainAddresses($scope.wallet, {}, function(err, addresses) {
if (err) {
ongoingProcess.set('gettingAddresses', false);
return popupService.showAlert(gettextCatalog.getString('Error'), err);
}
var allAddresses = addresses;
walletService.getBalance($scope.wallet, {}, function(err, resp) {
ongoingProcess.set('gettingAddresses', false);
if (err) {
return popupService.showAlert(gettextCatalog.getString('Error'), err);
}
withBalance = resp.byAddress;
var idx = lodash.indexBy(withBalance, 'address');
$scope.noBalance = lodash.reject(allAddresses, function(x) {
return idx[x.address];
});
processPaths($scope.noBalance);
processPaths(withBalance);
$scope.latestUnused = lodash.slice($scope.noBalance, 0, UNUSED_ADDRESS_LIMIT);
$scope.latestWithBalance = lodash.slice(withBalance, 0, BALANCE_ADDRESS_LIMIT);
lodash.each(withBalance, function(a) {
a.balanceStr = (a.amount * satToUnit).toFixed(unitDecimals) + ' ' + unitName;
});
$scope.viewAll = {
value: $scope.noBalance.length > UNUSED_ADDRESS_LIMIT || withBalance.length > BALANCE_ADDRESS_LIMIT
};
$scope.allAddresses = $scope.noBalance.concat(withBalance);
$scope.$digest();
});
});
};
function processPaths(list) {
lodash.each(list, function(n) {
n.path = n.path.replace(/^m/g, 'xpub');
});
};
$scope.newAddress = function() {
if ($scope.gapReached) return;
ongoingProcess.set('generatingNewAddress', true);
walletService.getAddress($scope.wallet, true, function(err, addr) {
if (err) {
ongoingProcess.set('generatingNewAddress', false);
$scope.gapReached = true;
$timeout(function() {
$scope.$digest();
});
return;
}
walletService.getMainAddresses($scope.wallet, {
limit: 1
}, function(err, _addr) {
ongoingProcess.set('generatingNewAddress', false);
if (err) return popupService.showAlert(gettextCatalog.getString('Error'), err);
if (addr != _addr[0].address) return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('New address could not be generated. Please try again.'));
$scope.noBalance = [_addr[0]].concat($scope.noBalance);
$scope.latestUnused = lodash.slice($scope.noBalance, 0, UNUSED_ADDRESS_LIMIT);
$scope.viewAll = {
value: $scope.noBalance.length > UNUSED_ADDRESS_LIMIT
};
$scope.$digest();
});
});
};
$scope.viewAllAddresses = function() {
$state.go('tabs.receive.allAddresses', {
walletId: $scope.wallet.id
});
};
$scope.showInformation = function() {
$timeout(function() {
$scope.showInfo = !$scope.showInfo;
$ionicScrollDelegate.resize();
});
};
$scope.readMore = function() {
$timeout(function() {
$scope.showMore = !$scope.showMore;
$ionicScrollDelegate.resize();
});
};
$scope.showMenu = function(allAddresses, $event) {
var scanObj = {
text: gettextCatalog.getString('Scan addresses for funds'),
action: scan,
};
var sendAddressesObj = {
text: gettextCatalog.getString('Send addresses by email'),
action: sendByEmail,
}
$scope.items = allAddresses ? [sendAddressesObj] : [scanObj];
$scope.height = $scope.items.length * MENU_ITEM_HEIGHT;
$ionicPopover.fromTemplateUrl('views/includes/menu-popover.html', {
scope: $scope
}).then(function(popover) {
$scope.menu = popover;
$scope.menu.show($event);
});
};
var scan = function() {
walletService.startScan($scope.wallet);
$scope.menu.hide();
$ionicHistory.clearHistory();
$state.go('tabs.home');
};
var sendByEmail = function() {
function formatDate(ts) {
var dateObj = new Date(ts * 1000);
if (!dateObj) {
$log.debug('Error formating a date');
return 'DateError';
}
if (!dateObj.toJSON()) {
return '';
}
return dateObj.toJSON();
};
ongoingProcess.set('sendingByEmail', true);
$timeout(function() {
var body = 'Copay Wallet "' + $scope.walletName + '" Addresses\n Only Main Addresses are shown.\n\n';
body += "\n";
body += $scope.allAddresses.map(function(v) {
return ('* ' + v.address + ' ' + 'xpub' + v.path.substring(1) + ' ' + formatDate(v.createdOn));
}).join("\n");
ongoingProcess.set('sendingByEmail', false);
window.plugins.socialsharing.shareViaEmail(
body,
'Copay Addresses',
null, // TO: must be null or an array
null, // CC: must be null or an array
null, // BCC: must be null or an array
null, // FILES: can be null, a string, or an array
function() {},
function() {}
);
$scope.menu.hide();
});
};
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.allAddressesView = data.stateName == 'tabs.receive.allAddresses' ? true : false;
$timeout(function() {
$scope.$apply();
});
});
$scope.$on("$ionicView.afterEnter", function(event, data) {
config = configService.getSync().wallet.settings;
unitToSatoshi = config.unitToSatoshi;
satToUnit = 1 / unitToSatoshi;
unitName = config.unitName;
unitDecimals = config.unitDecimals;
if (!$scope.allAddresses || $scope.allAddresses.length < 0) init();
});
});

View file

@ -1,62 +1,15 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesInformation',
function($scope, $log, $timeout, $ionicHistory, $ionicScrollDelegate, platformInfo, gettextCatalog, lodash, profileService, configService, $stateParams, walletService, $state) {
var base = 'xpub';
function($scope, $log, $ionicHistory, platformInfo, lodash, profileService, configService, $stateParams, $state) {
var wallet = profileService.getWallet($stateParams.walletId);
var walletId = wallet.id;
var config = configService.getSync();
var b = 1;
var colorCounter = 1;
var BLACK_WALLET_COLOR = '#202020';
$scope.isCordova = platformInfo.isCordova;
config.colorFor = config.colorFor || {};
$scope.sendAddrs = function() {
function formatDate(ts) {
var dateObj = new Date(ts * 1000);
if (!dateObj) {
$log.debug('Error formating a date');
return 'DateError';
}
if (!dateObj.toJSON()) {
return '';
}
return dateObj.toJSON();
};
$timeout(function() {
wallet.getMainAddresses({
doNotVerify: true
}, function(err, addrs) {
if (err) {
$log.warn(err);
return;
};
var body = 'Copay Wallet "' + $scope.walletName + '" Addresses\n Only Main Addresses are shown.\n\n';
body += "\n";
body += addrs.map(function(v) {
return ('* ' + v.address + ' ' + base + v.path.substring(1) + ' ' + formatDate(v.createdOn));
}).join("\n");
window.plugins.socialsharing.shareViaEmail(
body,
'Copay Addresses',
null, // TO: must be null or an array
null, // CC: must be null or an array
null, // BCC: must be null or an array
null, // FILES: can be null, a string, or an array
function() {},
function() {}
);
$timeout(function() {
$scope.$apply();
}, 1000);
});
}, 100);
};
$scope.saveBlack = function() {
function save(color) {
var opts = {
@ -71,14 +24,8 @@ angular.module('copayApp.controllers').controller('preferencesInformation',
});
};
if (b != 5) return b++;
save('#202020');
};
$scope.scan = function() {
walletService.startScan(wallet);
$ionicHistory.removeBackView();
$state.go('tabs.home');
if (colorCounter != 5) return colorCounter++;
save(BLACK_WALLET_COLOR);
};
$scope.$on("$ionicView.enter", function(event, data) {
@ -95,29 +42,5 @@ angular.module('copayApp.controllers').controller('preferencesInformation',
$scope.M = c.m;
$scope.N = c.n;
$scope.pubKeys = lodash.pluck(c.publicKeyRing, 'xPubKey');
$scope.addrs = null;
wallet.getMainAddresses({
doNotVerify: true
}, function(err, addrs) {
if (err) {
$log.warn(err);
return;
};
var last10 = [],
i = 0,
e = addrs.pop();
while (i++ < 10 && e) {
e.path = base + e.path.substring(1);
last10.push(e);
e = addrs.pop();
}
$scope.addrs = last10;
$timeout(function() {
$ionicScrollDelegate.resize();
$scope.$apply();
}, 10);
});
});
});

View file

@ -48,6 +48,12 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
}, 100);
};
$scope.showAddresses = function() {
$state.transitionTo('tabs.receive.addresses', {
walletId: $scope.wallet.credentials.walletId
});
};
$scope.openBackupNeededModal = function() {
$ionicModal.fromTemplateUrl('views/includes/backupNeededPopup.html', {
scope: $scope,

View file

@ -616,6 +616,31 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
/*
*
* Addresses
*
*/
.state('tabs.receive.addresses', {
url: '/addresses/:walletId',
views: {
'tab-receive@tabs': {
controller: 'addressesController',
templateUrl: 'views/addresses.html'
}
}
})
.state('tabs.receive.allAddresses', {
url: '/allAddresses/:walletId',
views: {
'tab-receive@tabs': {
controller: 'addressesController',
templateUrl: 'views/allAddresses.html'
}
}
})
/*
*
* Init backup flow

View file

@ -34,6 +34,9 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
'validatingWords': gettext('Validating recovery phrase...'),
'loadingTxInfo': gettext('Loading transaction info...'),
'sendingFeedback': gettext('Sending feedback...'),
'generatingNewAddress': gettext('Generating new address...'),
'gettingAddresses': gettext('Getting addresses...'),
'sendingByEmail': gettext('Preparing addresses...'),
};
root.clear = function() {

View file

@ -773,6 +773,21 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
});
};
root.getMainAddresses = function(wallet, opts, cb) {
opts = opts || {};
opts.reverse = true;
wallet.getMainAddresses(opts, function(err, addresses) {
return cb(err, addresses);
});
};
root.getBalance = function(wallet, opts, cb) {
opts = opts || {};
wallet.getBalance(opts, function(err, resp) {
return cb(err, resp);
});
};
root.getAddress = function(wallet, forceNew, cb) {
storageService.getLastAddress(wallet.id, function(err, addr) {
if (err) return cb(err);

View file

@ -0,0 +1,89 @@
#addresses {
.addr {
&-explanation, &-button-group {
padding: 0 1rem;
margin: 1rem 0;
}
&-description {
text-align: center;
font-size: 15px;
color: $mid-gray;
margin: 1rem 0;
a {
font-weight: bold;
cursor: pointer;
cursor: hand;
}
}
&-balance {
margin-top: 4px;
color: #5DD263;
}
&-path {
margin-top: 4px;
color: #B8B8B8;
}
}
.banner-icon {
margin-top: 25px;
i {
box-shadow: $hovering-box-shadow;
}
}
.addr-list {
.item {
color: $dark-gray;
padding-top: 1.3rem;
padding-bottom: 1.3rem;
&.has-addr-value {
padding-top: .65rem;
padding-bottom: .65rem;
}
&.item-divider {
color: $mid-gray;
padding-bottom: .5rem;
font-size: .9rem;
}
&.view-all {
margin: 20px 0px 20px 0px;
cursor: pointer;
cursor: hand;
i {
font-size: 35px;
margin-right: 5px;
color: #647ce8;
}
span {
color: #647ce8;
font-weight: bold;
}
}
i {
font-size: 35px;
margin-right: 2px;
}
}
.box-error {
padding: 25px;
background-color: #E65555;
color: #F4F4F4;
h5 {
margin: 5px;
color: #F4F4F4;
text-align: center;
font-weight: bold;
}
a {
font-weight: bold;
color: #F4F4F4;
cursor: pointer;
cursor: hand;
}
}
.item-note {
color: $light-gray;
}
}
}

View file

@ -0,0 +1,12 @@
#menu-popover {
border-radius: 5px;
.list {
.item {
cursor: pointer;
cursor: hand;
&:hover {
background-color: #E4E2E2;
}
}
}
}

View file

@ -89,6 +89,8 @@
.bit-address {
font-size: .8rem;
// left:10%;
cursor: pointer;
cursor: hand;
position: absolute;
transition: all .15s ease;
width:100%;
@ -117,7 +119,6 @@
.item {
padding-top: 5px;
padding-bottom: 5px;
display: inline-block;
font-size: .7rem;
@media(min-width:350px) {
font-size:.9rem;

View file

@ -15,6 +15,7 @@
@import "bitpayCardIntro";
@import "bitpayCardPreferences";
@import "address-book";
@import "addresses";
@import "wallet-backup-phrase";
@import "zero-state";
@import "onboarding/onboarding";
@ -26,6 +27,7 @@
@import "export";
@import "import";
@import "join";
@import "includes/menu-popover";
@import "includes/walletActivity";
@import "includes/wallets";
@import "includes/modals/modals";