This commit is contained in:
Gabriel Bazán 2016-05-18 17:28:12 -03:00 committed by Javier
parent 75be28b3bf
commit b4aadeb7be
4 changed files with 300 additions and 61 deletions

View File

@ -1,53 +1,53 @@
<nav class="sidebar" ng-controller="sidebarController as sidebar">
<header>
<logo ng-if="!sidebar.isWindowsPhoneApp" negative="true" width="80"></logo>
<img ng-if="sidebar.isWindowsPhoneApp" src="img/logo-negative.png" alt="Copay" width="80">
<div ng-include="'views/includes/version.html'"></div>
</header>
<ion-content overflow-scroll="true">
<ul class="pr">
<li ng-show="sidebar.wallets[0]"
ng-repeat="item in sidebar.wallets track by $index"
ng-class="{'selected': item.id == index.walletId}"
class="nav-item">
<a menu-toggle ng-click="$root.go('walletHome'); sidebar.switchWallet(item.id, index.walletId)" class="oh">
<div class="avatar-wallet"
ng-style="{'background-color':item.color}">
<i class="icon-wallet size-21"></i>
<header>
<logo ng-if="!sidebar.isWindowsPhoneApp" negative="true" width="80"></logo>
<img ng-if="sidebar.isWindowsPhoneApp" src="img/logo-negative.png" alt="Copay" width="80">
<div ng-include="'views/includes/version.html'"></div>
</header>
<ion-content overflow-scroll="true">
<ul class="pr">
<li ng-show="sidebar.wallets[0]"
ng-repeat="item in sidebar.wallets track by $index"
ng-class="{'selected': item.id == index.walletId}"
class="nav-item">
<a menu-toggle ng-click="$root.go('walletHome'); sidebar.switchWallet(item.id, index.walletId)" class="oh">
<div class="avatar-wallet"
ng-style="{'background-color':item.color}">
<i class="icon-wallet size-21"></i>
</div>
<div class="name-wallet" ng-class="{'m8t':item.n == 1}">{{item.name || item.id}}</div>
<div class="size-12" ng-show="item.n > 1" translate>{{item.m}}-of-{{item.n}}</div>
</a>
</li>
<li>
<a menu-toggle ng-click="$root.go('add')" class="oh">
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
<i class="fi-plus size-24 icon vm"></i>
<div class="tu text-bold">
<span class="size-12" translate>Add wallet</span>
</div>
<div class="name-wallet" ng-class="{'m8t':item.n == 1}">{{item.name || item.id}}</div>
<div class="size-12" ng-show="item.n > 1" translate>{{item.m}}-of-{{item.n}}</div>
<div translate>Create, join or import</div>
</a>
</li>
<li>
<a menu-toggle ng-click="$root.go('add')" class="oh">
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
<i class="fi-plus size-24 icon vm"></i>
<div class="tu text-bold">
<span class="size-12" translate>Add wallet</span>
</div>
<div translate>Create, join or import</div>
</a>
</li>
<li ng-show="!index.isWindowsPhoneApp && index.isComplete && (index.glideraEnabled || index.coinbaseEnabled)">
<a menu-toggle ng-click="$root.go('buyandsell')" class="oh">
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
<i class="icon-bank size-24 icon vm"></i>
<div class="tu text-bold m5t">
<span class="size-12" translate>Buy &amp; Sell</span>
</div>
</a>
</li>
<li>
<a menu-toggle ng-click="$root.go('preferencesGlobal')" class="oh">
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
<i class="fi-widget size-24 icon vm"></i>
<div class="tu text-bold">
<span class="size-12" translate>Settings</span>
</div>
<div translate>Global preferences</div>
</a>
</li>
</ul>
</ion-content>
</li>
<li ng-show="!index.isWindowsPhoneApp && index.isComplete && (index.glideraEnabled || index.coinbaseEnabled)">
<a menu-toggle ng-click="$root.go('buyandsell')" class="oh">
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
<i class="icon-bank size-24 icon vm"></i>
<div class="tu text-bold m5t">
<span class="size-12" translate>Buy &amp; Sell</span>
</div>
</a>
</li>
<li>
<a menu-toggle ng-click="$root.go('preferencesGlobal')" class="oh">
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
<i class="fi-widget size-24 icon vm"></i>
<div class="tu text-bold">
<span class="size-12" translate>Settings</span>
</div>
<div translate>Global preferences</div>
</a>
</li>
</ul>
</ion-content>
</nav>

View File

@ -54,7 +54,7 @@
-->
<ion-content id="walletHome" class="walletHome tab-view tab-in" scroll="false">
<ion-content>
<ion-content delegate-handle="balance" on-scroll="freezeScroll()">
<ion-refresher
pulling-icon="ion-ios-refresh"
on-refresh="index.updateAll({triggerTxUpdate: true})">
@ -62,12 +62,12 @@
<div class="oh pr">
<div ng-style="{'background-color':index.backgroundColor}" ng-class="{amount: !shouldCollapse, amountcollapsed: shouldCollapse}">
<div ng-if="!index.anyOnGoingProcess && !index.notAuthorized">
<div class="m15t" ng-show="index.updateError" ng-click='index.updateAll({triggerTxUpdate: true})'>
<div class="m15t" ng-show="index.updateError && !shouldCollapse" ng-click='index.updateAll({triggerTxUpdate: true})'>
<span class="size-12 db m10b">{{index.updateError|translate}}</span>
<button class="outline white tiny round" translate>Tap to retry</button>
</div>
<div ng-show="index.walletScanStatus == 'error'" ng-click='index.retryScan()'>
<div ng-show="index.walletScanStatus == 'error' && !shouldCollapse" ng-click='index.retryScan()'>
<span translate>Scan status finished with error</span>
<br><span translate>Tap to retry</span>
</div>
@ -83,7 +83,7 @@
</div>
</div>
<div ng-show="index.shouldHideBalance" on-hold="index.onHold()">
<div ng-show="!index.updateError && index.walletScanStatus != 'error' && index.shouldHideBalance" on-hold="index.onHold()">
<strong class="size-24" translate>[Balance Hidden]</strong>
<div class="size-14" ng-if="!shouldCollapse" transalate>
Tap and hold to show
@ -106,8 +106,7 @@
</div>
</div> <!-- oh -->
</ion-content>
<ion-content overflow-scroll="true" ng-class="{m150t: !shouldCollapse, m50t: shouldCollapse}" delegate-handle="transactions" on-scroll="getScrollPosition()">
<ion-content overflow-scroll="true" ng-class="{m150t: !shouldCollapse, m50t: shouldCollapse}" delegate-handle="transactions" on-scroll="collapseBalanceContent(index.updatingTxHistory && index.txProgress > 5)">
<div class="m50b">
<div class="oh pr m20t" ng-show="index.incorrectDerivation">
<div class="text-center text-warning">
@ -157,7 +156,7 @@
</div>
<!-- Activity -->
<h4 class="title" ng-click="index.startSearch(); openModal()" ng-show="!index.notAuthorized">
<span translate>Activity</span>
<i class="dib m5l size-16 pointer fi-magnifying-glass"></i>

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $ionicScrollDelegate, $rootScope, $interval, $timeout, $filter, $modal, $log, $ionicModal, notification, txStatus, profileService, lodash, configService, rateService, storageService, bitcore, gettext, gettextCatalog, platformInfo, addressService, ledger, bwsError, confirmDialog, txFormatService, animationService, addressbookService, go, feeService, walletService, fingerprintService, nodeWebkit) {
angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $ionicScrollDelegate, $ionicSideMenuDelegate, $rootScope, $interval, $timeout, $filter, $modal, $log, $ionicModal, notification, txStatus, profileService, lodash, configService, rateService, storageService, bitcore, gettext, gettextCatalog, platformInfo, addressService, ledger, bwsError, confirmDialog, txFormatService, animationService, addressbookService, go, feeService, walletService, fingerprintService, nodeWebkit) {
var isCordova = platformInfo.isCordova;
var isWP = platformInfo.isWP;
@ -32,12 +32,29 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
ret.sendMaxInfo = {};
var vanillaScope = ret;
$scope.getScrollPosition = function() {
$scope.shouldCollapse = $ionicScrollDelegate.$getByHandle('transactions').getScrollPosition().top > 50;
$scope.collapseBalanceContent = function(val) {
if (val) return;
$scope.shouldCollapse = $ionicScrollDelegate.$getByHandle('transactions').getScrollPosition().top > 50 ? true : false;
$timeout(function() {
$scope.$apply();
});
}
};
$scope.freezeScroll = function() {
if ($ionicScrollDelegate.$getByHandle('balance').getScrollPosition().top < -75) {
$ionicScrollDelegate.$getByHandle('balance').freezeScroll(true);
return;
}
if ($ionicSideMenuDelegate.getOpenRatio() != 0)
$ionicScrollDelegate.$getByHandle('balance').freezeScroll(true);
else
$ionicScrollDelegate.$getByHandle('balance').freezeScroll(false);
$timeout(function() {
$scope.$apply();
});
};
var disableScannerListener = $rootScope.$on('dataScanned', function(event, data) {
self.setForm(data);
@ -1425,3 +1442,226 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
}
});
out(function() {
$rootScope.$digest();
}, 1);
return cb(true);
}
self._paypro = paypro;
self.setForm(paypro.toAddress, (paypro.amount * satToUnit).toFixed(self.unitDecimals), paypro.memo);
_paymentTimeControl(paypro.expires);
return cb();
});
}, 1);
};
function _paymentTimeControl(expirationTime) {
self.paymentExpired = false;
setExpirationTime();
self.countDown = $interval(function() {
setExpirationTime();
}, 1000);
function setExpirationTime() {
var now = Math.floor(Date.now() / 1000);
if (now > expirationTime) {
setExpiredValues();
return;
}
var totalSecs = expirationTime - now;
var m = Math.floor(totalSecs / 60);
var s = totalSecs % 60;
self.remainingTimeStr = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2);
};
function setExpiredValues() {
self.paymentExpired = true;
self.remainingTimeStr = null;
self._paypro = null;
self.error = gettext('Cannot sign: The payment request has expired');
if (self.countDown) $interval.cancel(self.countDown);
};
};
this.setFromUri = function(uri) {
var self = this;
function sanitizeUri(uri) {
// Fixes when a region uses comma to separate decimals
var regex = /[\?\&]amount=(\d+([\,\.]\d+)?)/i;
var match = regex.exec(uri);
if (!match || match.length === 0) {
return uri;
}
var value = match[0].replace(',', '.');
var newUri = uri.replace(regex, value);
return newUri;
};
var satToUnit = 1 / this.unitToSatoshi;
// URI extensions for Payment Protocol with non-backwards-compatible request
if ((/^bitcoin:\?r=[\w+]/).exec(uri)) {
uri = decodeURIComponent(uri.replace('bitcoin:?r=', ''));
this.setFromPayPro(uri, function(err) {
if (err) {
return err;
}
});
} else {
uri = sanitizeUri(uri);
if (!bitcore.URI.isValid(uri)) {
return uri;
}
var parsed = new bitcore.URI(uri);
var addr = parsed.address ? parsed.address.toString() : '';
var message = parsed.message;
var amount = parsed.amount ?
(parsed.amount.toFixed(0) * satToUnit).toFixed(this.unitDecimals) : 0;
if (parsed.r) {
this.setFromPayPro(parsed.r, function(err) {
if (err && addr && amount) {
self.setForm(addr, amount, message);
return addr;
}
});
} else {
this.setForm(addr, amount, message);
return addr;
}
}
};
this.onAddressChange = function(value) {
this.resetError();
if (!value) return '';
if (this._paypro)
return value;
if (value.indexOf('bitcoin:') === 0) {
return this.setFromUri(value);
} else if (/^https?:\/\//.test(value)) {
return this.setFromPayPro(value);
} else {
return value;
}
};
// History
function strip(number) {
return (parseFloat(number.toPrecision(12)));
}
this.getUnitName = function() {
return this.unitName;
};
this.getAlternativeIsoCode = function() {
return this.alternativeIsoCode;
};
this.openTxModal = function(tx) {
$rootScope.$emit('Local/TxModal', tx);
};
this.hasAction = function(actions, action) {
return actions.hasOwnProperty('create');
};
this.sendMax = function(availableBalanceSat) {
if (availableBalanceSat == 0) {
this.error = gettext("Cannot create transaction. Insufficient funds");
return;
}
var self = this;
var fc = profileService.focusedClient;
this.error = null;
this.setOngoingProcess(gettextCatalog.getString('Calculating fee'));
feeService.getCurrentFeeValue(function(err, feePerKb) {
if (err || !lodash.isNumber(feePerKb)) {
self.setOngoingProcess();
self.error = gettext('Could not get fee value');
return;
}
var opts = {};
opts.feePerKb = feePerKb;
opts.returnInputs = true;
var config = configService.getSync();
opts.excludeUnconfirmedUtxos = !config.wallet.spendUnconfirmed;
self.setOngoingProcess(gettextCatalog.getString('Retrieving inputs information'));
fc.getSendMaxInfo(opts, function(err, resp) {
self.setOngoingProcess();
if (err) {
self.error = err;
$scope.$apply();
return;
}
if (resp.amount == 0) {
self.error = gettext("Not enough funds for fee");
$scope.$apply();
return;
}
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees", {
fee: profileService.formatAmount(resp.fee) + ' ' + self.unitName
});
var warningMsg = verifyExcludedUtxos();
if (!lodash.isEmpty(warningMsg))
msg += '. \n' + warningMsg;
confirmDialog.show(msg, function(confirmed) {
if (confirmed) {
self.sendMaxInfo = resp;
var amount = parseFloat((resp.amount * self.satToUnit).toFixed(self.unitDecimals));
self.setForm(null, amount, null);
} else {
self.resetForm();
}
});
function verifyExcludedUtxos() {
var warningMsg = [];
if (resp.utxosBelowFee > 0) {
warningMsg.push(gettextCatalog.getString("Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", {
amountBelowFeeStr: profileService.formatAmount(resp.amountBelowFee) + ' ' + self.unitName
}));
}
if (resp.utxosAboveMaxSize > 0) {
warningMsg.push(gettextCatalog.getString("Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded", {
amountAboveMaxSizeStr: profileService.formatAmount(resp.amountAboveMaxSize) + ' ' + self.unitName
}));
}
return warningMsg.join('\n');
}
});
});
};
/* Start setup */
lodash.assign(self, vanillaScope);
this.bindTouchDown();
if (profileService.focusedClient) {
this.setAddress();
this.setSendFormInputs();
}
});

View File

@ -26,7 +26,7 @@ angular.module('copayApp.services').factory('go', function($window, $ionicSideMe
};
root.toggleLeftMenu = function() {
$ionicSideMenuDelegate.toggleLeft()
$ionicSideMenuDelegate.toggleLeft();
};
root.walletHome = function() {