add proposal modal
This commit is contained in:
parent
1bd9be869c
commit
4142624f41
9 changed files with 445 additions and 453 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<ion-modal-view ng-controller="addressbookController as addressbookC">
|
||||
<div ng-init="wallets[0] ? selectedWalletsOpt = true : selectedWalletsOpt = false; checkClipboard()">
|
||||
<ion-content>
|
||||
<ion-content ng-style="{'background-color': '#f6f7f9'}">
|
||||
<nav class="tab-bar" ng-style="{'background-color':color}">
|
||||
<section class="left-small">
|
||||
<a ng-show="!editAddressbook && !addAddressbookEntry" ng-click="cancel()" class="p10">
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
</nav>
|
||||
|
||||
<ion-content>
|
||||
<div class="header-modal text-center">
|
||||
<div class="header-modal text-center p50t">
|
||||
<div class="size-42">
|
||||
{{unitTotal}} {{unitName}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
<ion-modal-view class="txModal" ng-controller="txDetailsController">
|
||||
<ion-content>
|
||||
<nav class="tab-bar" ng-style="{'background-color':color}">
|
||||
<section class="left-small">
|
||||
<a ng-click="cancel()">
|
||||
<i class="icon-arrow-left3 icon-back"></i>
|
||||
<span class="text-back" translate>Back</span>
|
||||
</a>
|
||||
</section>
|
||||
<section class="middle tab-bar-section">
|
||||
<h1 class="title ellipsis" translate>
|
||||
Transaction
|
||||
</h1>
|
||||
</section>
|
||||
</nav>
|
||||
<ion-modal-view ng-controller="txDetailsController">
|
||||
<nav class="tab-bar" ng-style="{'background-color':color}">
|
||||
<section class="left-small">
|
||||
<a ng-click="cancel()" class="p10">
|
||||
<span class="text-close" translate>Close</span>
|
||||
</a>
|
||||
</section>
|
||||
<section class="middle tab-bar-section">
|
||||
<h1 class="title ellipsis" translate>
|
||||
Transaction
|
||||
</h1>
|
||||
</section>
|
||||
</nav>
|
||||
|
||||
<div class="txModal-content">
|
||||
<ion-content>
|
||||
<div class="modal-content">
|
||||
<div class="header-modal text-center" ng-init="getAlternativeAmount(btx)">
|
||||
<div ng-show="btx.action != 'invalid'">
|
||||
<div ng-show="btx.action == 'received'">
|
||||
|
|
|
|||
|
|
@ -1,193 +1,181 @@
|
|||
<nav class="tab-bar" ng-style="{'background-color':color}">
|
||||
<section class="left-small">
|
||||
<a ng-click="cancel()">
|
||||
<i class="icon-arrow-left3 icon-back"></i>
|
||||
<span class="text-back" translate>Back</span>
|
||||
</a>
|
||||
</section>
|
||||
<section class="middle tab-bar-section">
|
||||
<h1 class="title ellipsis" translate>
|
||||
Payment Proposal
|
||||
</h1>
|
||||
</section>
|
||||
</nav>
|
||||
<div class="modal-content fix-modals-touch"
|
||||
ng-swipe-disable-mouse
|
||||
ng-swipe-right="cancel()"
|
||||
ng-init="updateCopayerList()">
|
||||
<div class="payment-proposal-head"
|
||||
ng-style="{'background-color':color}">
|
||||
<div class="size-36">{{tx.amountStr}}</div>
|
||||
<div class="size-14 text-light" ng-show="tx.alternativeAmountStr">{{tx.alternativeAmountStr}}</div>
|
||||
<i class="db fi-arrow-down size-24 m10v"></i>
|
||||
<span class="payment-proposal-to"
|
||||
ng-click="copyToClipboard(tx.toAddress)">
|
||||
<i class="fi-bitcoin left"></i>
|
||||
<contact ng-if="!tx.hasMultiplesOutputs" class="dib enable_text_select ellipsis m5t m5b size-14" address="{{tx.toAddress}}"></contact>
|
||||
<span ng-if="tx.hasMultiplesOutputs" translate>
|
||||
Multiple recipients
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<ion-modal-view ng-controller="txpDetailsController">
|
||||
<nav class="tab-bar" ng-style="{'background-color':color}">
|
||||
<section class="left-small">
|
||||
<a ng-click="cancel()" class="p10">
|
||||
<span class="text-close" translate>Close</span>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<div class="oh">
|
||||
<div class="box-notification" ng-show="error">
|
||||
<span class="text-warning size-14">
|
||||
{{error|translate}}
|
||||
</span>
|
||||
</div>
|
||||
<section class="middle tab-bar-section">
|
||||
<h1 class="title ellipsis" translate>Payment Proposal</h1>
|
||||
</section>
|
||||
</nav>
|
||||
|
||||
<div class="row" ng-if="tx.removed">
|
||||
<div class="column m20t text-center text-warning size-12" translate>
|
||||
The payment was removed by creator
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row p20t white" ng-if="tx.pendingForUs">
|
||||
<div class="large-6 medium-6 small-6 columns" ng-show="isShared">
|
||||
<button class="button outline round dark-gray expand" ng-click="reject(tx);"
|
||||
ng-disabled="loading">
|
||||
<i class="fi-x"></i>
|
||||
<span translate>Reject</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="large-6 medium-6 small-6 columns text-right" ng-show="canSign">
|
||||
<button class="button primary round expand" ng-click="sign(tx)"
|
||||
ng-style="{'background-color':color}"
|
||||
ng-disabled="loading || paymentExpired">
|
||||
<i class="fi-check"></i>
|
||||
<span translate>Accept</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center text-gray size-12 m20t" ng-show="tx.status != 'pending'">
|
||||
<div ng-show="tx.status=='accepted' && !tx.isGlidera">
|
||||
<div class="m10b" translate>Payment accepted, but not yet broadcasted</div>
|
||||
|
||||
<button class="primary round m0"
|
||||
ng-style="{'background-color':color}"
|
||||
ng-click="broadcast(tx)"
|
||||
ng-disabled="loading"
|
||||
> <i class="fi-upload-cloud"></i>
|
||||
<span translate>Broadcast Payment</span>
|
||||
</button>
|
||||
</div>
|
||||
<div ng-show="tx.status=='accepted' && tx.isGlidera" >
|
||||
<div class="m10h" translate>Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.</div>
|
||||
</div>
|
||||
<div class="text-success"
|
||||
ng-show="tx.status=='broadcasted'" translate>
|
||||
Payment Sent
|
||||
</div>
|
||||
<div class="text-warning"
|
||||
ng-show="tx.status=='rejected'" translate>
|
||||
Payment Rejected
|
||||
</div>
|
||||
<div class="onGoingProcess" ng-show="loading">
|
||||
<div class="onGoingProcess-content" ng-style="{'background-color':index.backgroundColor}">
|
||||
<ion-spinner class="spinner-stable" icon="lines"></ion-spinner>
|
||||
<span translate>{{loading}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="title m0" translate>Details</h4>
|
||||
<ul class="no-bullet size-14 m0">
|
||||
<li class="line-b p10 oh" ng-show="tx.message">
|
||||
<span class="text-gray" translate>Note</span>
|
||||
<span class="right">{{tx.message}}</span>
|
||||
</li>
|
||||
<ion-content>
|
||||
<div class="modal-content fix-modals-touch" ng-init="updateCopayerList()">
|
||||
<div class="payment-proposal-head" ng-style="{'background-color':color}">
|
||||
<div class="size-36">{{tx.amountStr}}</div>
|
||||
<div class="size-14 text-light" ng-show="tx.alternativeAmountStr">{{tx.alternativeAmountStr}}</div>
|
||||
<i class="db fi-arrow-down size-24 m10v"></i>
|
||||
<span class="payment-proposal-to" ng-click="copyToClipboard(tx.toAddress)">
|
||||
<i class="fi-bitcoin left"></i>
|
||||
<contact ng-if="!tx.hasMultiplesOutputs" class="dib enable_text_select ellipsis m5t m5b size-14" address="{{tx.toAddress}}"></contact>
|
||||
<span ng-if="tx.hasMultiplesOutputs" translate>Multiple recipients</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<li ng-show="tx.hasMultiplesOutputs" class="line-b p10 oh"
|
||||
ng-click="showMultiplesOutputs = !showMultiplesOutputs">
|
||||
<span class="text-gray" translate>Recipients</span>
|
||||
<span class="right">{{tx.recipientCount}}
|
||||
<i ng-show="showMultiplesOutputs" class="icon-arrow-up3 size-24"></i>
|
||||
<i ng-show="!showMultiplesOutputs" class="icon-arrow-down3 size-24"></i>
|
||||
</span>
|
||||
</li>
|
||||
<div class="oh">
|
||||
<div class="box-notification" ng-show="error">
|
||||
<span class="text-warning size-14" translate>{{error}}</span>
|
||||
</div>
|
||||
|
||||
<div class="line-b" ng-show="tx.hasMultiplesOutputs && showMultiplesOutputs"
|
||||
ng-repeat="output in tx.outputs"
|
||||
ng-include="'views/includes/output.html'">
|
||||
</div>
|
||||
<div class="row" ng-if="tx.removed">
|
||||
<div class="column m20t text-center text-warning size-12" translate>
|
||||
The payment was removed by creator
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray" translate>Fee</span>
|
||||
<span class="right">{{tx.feeStr}}</span>
|
||||
</li>
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray" translate>Time</span>
|
||||
<span class="right">
|
||||
<time>{{ (tx.ts || tx.createdOn ) * 1000 | amTimeAgo}}</time>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p10 oh">
|
||||
<span class="text-gray" translate>Created by</span>
|
||||
<span class="right">{{tx.creatorName}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="p10 text-center size-12" ng-show="!currentSpendUnconfirmed && tx.hasUnconfirmedInputs">
|
||||
<span class="text-warning" translate>Warning: this transaction has unconfirmed inputs</span>
|
||||
</div>
|
||||
<div class="row p20t white" ng-if="tx.pendingForUs">
|
||||
<div class="large-6 medium-6 small-6 columns" ng-show="isShared">
|
||||
<button class="button outline round dark-gray expand" ng-click="reject(tx)" ng-disabled="loading">
|
||||
<i class="fi-x"></i>
|
||||
<span translate>Reject</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="large-6 medium-6 small-6 columns text-right" ng-show="canSign">
|
||||
<button class="button primary round expand" ng-click="sign(tx)" ng-style="{'background-color':color}" ng-disabled="loading || paymentExpired">
|
||||
<i class="fi-check"></i>
|
||||
<span translate>Accept</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="tx.paypro">
|
||||
<h4 class="title m0" translate>Payment details</h4>
|
||||
<ul class="no-bullet size-14 m0">
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray" translate>To</span>
|
||||
<span class="right">
|
||||
<span>
|
||||
<span ng-show="tx.merchant.pr.ca"><i class="fi-lock"></i> {{tx.paypro.domain}}</span>
|
||||
<span ng-show="!tx.merchant.pr.ca"><i class="fi-unlock"></i> {{tx.paypro.domain}}</span>
|
||||
<div class="text-center text-gray size-12 m20t" ng-show="tx.status != 'pending'">
|
||||
<div ng-show="tx.status=='accepted' && !tx.isGlidera">
|
||||
<div class="m10b" translate>Payment accepted, but not yet broadcasted</div>
|
||||
|
||||
<button class="primary round m0" ng-style="{'background-color':color}" ng-click="broadcast(tx)" ng-disabled="loading">
|
||||
<i class="fi-upload-cloud"></i>
|
||||
<span translate>Broadcast Payment</span>
|
||||
</button>
|
||||
</div>
|
||||
<div ng-show="tx.status=='accepted' && tx.isGlidera" >
|
||||
<div class="m10h" translate>Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.</div>
|
||||
</div>
|
||||
<div class="text-success" ng-show="tx.status == 'broadcasted'" translate>Payment Sent</div>
|
||||
<div class="text-warning" ng-show="tx.status=='rejected'" translate>Payment Rejected</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="title m0" translate>Details</h4>
|
||||
|
||||
<ul class="no-bullet size-14 m0">
|
||||
<li class="line-b p10 oh" ng-show="tx.message">
|
||||
<span class="text-gray" translate>Note</span>
|
||||
<span class="right">{{tx.message}}</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.hasMultiplesOutputs" class="line-b p10 oh" ng-click="showMultiplesOutputs = !showMultiplesOutputs">
|
||||
<span class="text-gray" translate>Recipients</span>
|
||||
<span class="right">{{tx.recipientCount}}
|
||||
<i ng-show="showMultiplesOutputs" class="icon-arrow-up3 size-24"></i>
|
||||
<i ng-show="!showMultiplesOutputs" class="icon-arrow-down3 size-24"></i>
|
||||
</span>
|
||||
<contact address="{{tx.toAddress}}" ng-hide="tx.merchant"></contact>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p10" ng-if="paymentExpired">
|
||||
<span class="text-gray" translate>Expired</span>
|
||||
<span class="right text-alert">
|
||||
<time>{{tx.paypro.expires * 1000 | amTimeAgo }}</time>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p10" ng-if="!paymentExpired">
|
||||
<span class="text-gray" translate>Expires</span>
|
||||
<span class="right">
|
||||
<time>{{expires}}</time>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray">Merchant Message</span>
|
||||
<span class="db">{{tx.paypro.pr.pd.memo}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<div ng-if="tx.actions[0] && !txRejected && !txBroadcasted">
|
||||
<h4 class="title m0">
|
||||
<div class="right size-12 text-gray m10r">
|
||||
{{tx.requiredSignatures}}/{{tx.walletN}}
|
||||
<div class="line-b" ng-show="tx.hasMultiplesOutputs && showMultiplesOutputs"
|
||||
ng-repeat="output in tx.outputs" ng-include="'views/includes/output.html'">
|
||||
</div>
|
||||
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray" translate>Fee</span>
|
||||
<span class="right">{{tx.feeStr}}</span>
|
||||
</li>
|
||||
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray" translate>Time</span>
|
||||
<span class="right">
|
||||
<time>{{ (tx.ts || tx.createdOn ) * 1000 | amTimeAgo}}</time>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li class="line-b p10 oh">
|
||||
<span class="text-gray" translate>Created by</span>
|
||||
<span class="right">{{tx.creatorName}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="p10 text-center size-12" ng-show="!currentSpendUnconfirmed && tx.hasUnconfirmedInputs">
|
||||
<span class="text-warning" translate>Warning: this transaction has unconfirmed inputs</span>
|
||||
</div>
|
||||
<span translate>Participants</span>
|
||||
</h4>
|
||||
<ul class="no-bullet size-14 m0">
|
||||
<li class="line-b p10 text-gray" ng-repeat="ac in tx.actions">
|
||||
<i class="icon-contact size-24"></i>
|
||||
<span class="right">
|
||||
<i ng-if="ac.type == 'reject'" class="fi-x icon-sign x db"></i>
|
||||
<i ng-if="ac.type == 'accept'" class="fi-check icon-sign check db"></i>
|
||||
</span>
|
||||
{{ac.copayerName}} <span ng-if="ac.copayerId == copayerId">({{'Me'|translate}})</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="columns text-center m20t" ng-if="tx.canBeRemoved || (tx.status == 'accepted' && !tx.broadcastedOn)">
|
||||
<div class="text-gray size-12 m20b" ng-show="!tx.isGlidera && isShared" translate>
|
||||
* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.
|
||||
<div ng-if="tx.paypro">
|
||||
<h4 class="title m0" translate>Payment details</h4>
|
||||
<ul class="no-bullet size-14 m0">
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray" translate>To</span>
|
||||
<span class="right">
|
||||
<span>
|
||||
<span ng-show="tx.merchant.pr.ca"><i class="fi-lock"></i> {{tx.paypro.domain}}</span>
|
||||
<span ng-show="!tx.merchant.pr.ca"><i class="fi-unlock"></i> {{tx.paypro.domain}}</span>
|
||||
</span>
|
||||
<contact address="{{tx.toAddress}}" ng-hide="tx.merchant"></contact>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p10" ng-if="paymentExpired">
|
||||
<span class="text-gray" translate>Expired</span>
|
||||
<span class="right text-alert">
|
||||
<time>{{tx.paypro.expires * 1000 | amTimeAgo }}</time>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p10" ng-if="!paymentExpired">
|
||||
<span class="text-gray" translate>Expires</span>
|
||||
<span class="right">
|
||||
<time>{{expires}}</time>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p10">
|
||||
<span class="text-gray">Merchant Message</span>
|
||||
<span class="db">{{tx.paypro.pr.pd.memo}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div ng-if="tx.actions[0] && !txRejected && !txBroadcasted">
|
||||
<h4 class="title m0">
|
||||
<div class="right size-12 text-gray m10r">
|
||||
{{tx.requiredSignatures}}/{{tx.walletN}}
|
||||
</div>
|
||||
<span translate>Participants</span>
|
||||
</h4>
|
||||
<ul class="no-bullet size-14 m0">
|
||||
<li class="line-b p10 text-gray" ng-repeat="ac in tx.actions">
|
||||
<i class="icon-contact size-24"></i>
|
||||
<span class="right">
|
||||
<i ng-if="ac.type == 'reject'" class="fi-x icon-sign x db"></i>
|
||||
<i ng-if="ac.type == 'accept'" class="fi-check icon-sign check db"></i>
|
||||
</span>
|
||||
{{ac.copayerName}} <span ng-if="ac.copayerId == copayerId" translate>({{'Me'}})</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="columns text-center m20t" ng-if="tx.canBeRemoved || (tx.status == 'accepted' && !tx.broadcastedOn)">
|
||||
<div class="text-gray size-12 m20b" ng-show="!tx.isGlidera && isShared" translate>
|
||||
* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.
|
||||
</div>
|
||||
<button class="tiny round outline dark-gray warning" ng-click="remove(tx)" ng-disabled="loading">
|
||||
<i class="fi-trash size-14 m5r"></i>
|
||||
<span translate>Delete Payment Proposal</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="tiny round outline dark-gray warning" ng-click="remove(tx)"
|
||||
ng-disabled="loading">
|
||||
<i class="fi-trash size-14 m5r"></i>
|
||||
<span translate>Delete Payment Proposal</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="extra-margin-bottom"></div>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-modal-view>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@
|
|||
<strong class="size-36">{{index.totalBalanceStr}}</strong>
|
||||
<div class="size-14" ng-if="index.totalBalanceAlternative">{{index.totalBalanceAlternative}} {{index.alternativeIsoCode}}</div>
|
||||
<div class="size-14" ng-if="index.pendingAmount">
|
||||
<span translate>Pending Confirmation</span>:{{index.pendingAmountStr}}
|
||||
<span translate>Pending Confirmation</span>: {{index.pendingAmountStr}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
|
|||
}
|
||||
$rootScope.$apply();
|
||||
});
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// This handles errors from BWS/index which normally
|
||||
|
|
|
|||
240
src/js/controllers/modals/txpDetails.js
Normal file
240
src/js/controllers/modals/txpDetails.js
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('txpDetailsController', function($scope, $rootScope, $timeout, $interval, txStatus, $ionicScrollDelegate, txFormatService, fingerprintService, bwsError, isChromeApp, gettextCatalog, lodash, profileService, walletService) {
|
||||
var self = $scope.self;
|
||||
var tx = $scope.tx;
|
||||
var copayers = $scope.copayers;
|
||||
var isGlidera = $scope.isGlidera;
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
var fc = profileService.focusedClient;
|
||||
$scope.loading = null;
|
||||
$scope.copayerId = fc.credentials.copayerId;
|
||||
$scope.isShared = fc.credentials.n > 1;
|
||||
$scope.canSign = fc.canSign() || fc.isPrivKeyExternal();
|
||||
$scope.color = fc.backgroundColor;
|
||||
|
||||
checkPaypro();
|
||||
|
||||
// ToDo: use tx.customData instead of tx.message
|
||||
if (tx.message === 'Glidera transaction' && isGlidera) {
|
||||
tx.isGlidera = true;
|
||||
if (tx.canBeRemoved) {
|
||||
tx.canBeRemoved = (Date.now() / 1000 - (tx.ts || tx.createdOn)) > GLIDERA_LOCK_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.sign = function(txp) {
|
||||
$scope.error = null;
|
||||
$scope.loading = 'Signing Transaction';
|
||||
|
||||
fingerprintService.check(fc, function(err) {
|
||||
if (err) {
|
||||
$scope.error = err;
|
||||
$scope.loading = null;
|
||||
return;
|
||||
}
|
||||
|
||||
handleEncryptedWallet(function(err) {
|
||||
if (err) {
|
||||
$scope.error = err;
|
||||
$scope.loading = null;
|
||||
return;
|
||||
}
|
||||
|
||||
walletService.signTx(fc, txp, function(err, signedTxp) {
|
||||
walletService.lock(fc);
|
||||
if (err) {
|
||||
$scope.error = err;
|
||||
$scope.loading = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (signedTxp.status == 'accepted') {
|
||||
$scope.loading = 'Broadcasting Transaction';
|
||||
walletService.broadcastTx(fc, signedTxp, function(err, broadcastedTxp) {
|
||||
$scope.loading = null;
|
||||
$scope.$emit('UpdateTx');
|
||||
$scope.close(broadcastedTxp);
|
||||
if (err) {
|
||||
$scope.error = err;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$scope.loading = null;
|
||||
$scope.$emit('UpdateTx');
|
||||
$scope.close(signedTxp);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.reject = function(txp) {
|
||||
$scope.loading = 'Rejecting payment';
|
||||
$scope.error = null;
|
||||
|
||||
$timeout(function() {
|
||||
walletService.rejectTx(fc, txp, function(err, txpr) {
|
||||
$scope.loading = null;
|
||||
|
||||
if (err) {
|
||||
$scope.$emit('UpdateTx');
|
||||
$scope.error = bwsError.msg(err, gettextCatalog.getString('Could not reject payment'));
|
||||
$scope.$digest();
|
||||
} else {
|
||||
$scope.close(txpr);
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
};
|
||||
|
||||
$scope.remove = function(txp) {
|
||||
$scope.loading = 'Deleting Payment';
|
||||
$scope.error = null;
|
||||
|
||||
$timeout(function() {
|
||||
walletService.removeTx(fc, txp, function(err) {
|
||||
$scope.loading = null;
|
||||
|
||||
// Hacky: request tries to parse an empty response
|
||||
if (err && !(err.message && err.message.match(/Unexpected/))) {
|
||||
$scope.$emit('UpdateTx');
|
||||
$scope.error = bwsError.msg(err, gettextCatalog.getString('Could not delete payment proposal'));
|
||||
$scope.$digest();
|
||||
return;
|
||||
}
|
||||
$scope.close();
|
||||
});
|
||||
}, 10);
|
||||
};
|
||||
|
||||
$scope.broadcast = function(txp) {
|
||||
$scope.loading = 'Broadcasting Payment';
|
||||
$scope.error = null;
|
||||
|
||||
$timeout(function() {
|
||||
walletService.broadcastTx(fc, txp, function(err, txpb) {
|
||||
$scope.loading = null;
|
||||
|
||||
if (err) {
|
||||
$scope.error = bwsError.msg(err, gettextCatalog.getString('Could not broadcast payment'));
|
||||
$scope.$digest();
|
||||
return;
|
||||
}
|
||||
$scope.close(txpb);
|
||||
});
|
||||
}, 10);
|
||||
};
|
||||
|
||||
$scope.getShortNetworkName = function() {
|
||||
return fc.credentials.networkName.substring(0, 4);
|
||||
};
|
||||
|
||||
function checkPaypro() {
|
||||
if (tx.payProUrl && !isChromeApp) {
|
||||
fc.fetchPayPro({
|
||||
payProUrl: tx.payProUrl,
|
||||
}, function(err, paypro) {
|
||||
if (err) return;
|
||||
tx.paypro = paypro;
|
||||
paymentTimeControl(tx.paypro.expires);
|
||||
$timeout(function() {
|
||||
$ionicScrollDelegate.resize();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function paymentTimeControl(expirationTime) {
|
||||
$scope.paymentExpired = false;
|
||||
setExpirationTime();
|
||||
|
||||
self.countDown = $interval(function() {
|
||||
setExpirationTime();
|
||||
}, 1000);
|
||||
|
||||
function setExpirationTime() {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
if (now > expirationTime) {
|
||||
$scope.paymentExpired = true;
|
||||
if (self.countDown) $interval.cancel(self.countDown);
|
||||
return;
|
||||
}
|
||||
var totalSecs = expirationTime - now;
|
||||
var m = Math.floor(totalSecs / 60);
|
||||
var s = totalSecs % 60;
|
||||
$scope.expires = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2);
|
||||
};
|
||||
};
|
||||
|
||||
lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy', 'transactionProposalRemoved', 'TxProposalRemoved', 'NewOutgoingTx', 'UpdateTx'], function(eventName) {
|
||||
$scope.$on(eventName, function() {
|
||||
fc.getTx($scope.tx.id, function(err, tx) {
|
||||
if (err) {
|
||||
if (err.message && err.message == 'TX_NOT_FOUND' &&
|
||||
(eventName == 'transactionProposalRemoved' || eventName == 'TxProposalRemoved')) {
|
||||
$scope.tx.removed = true;
|
||||
$scope.tx.canBeRemoved = false;
|
||||
$scope.tx.pendingForUs = false;
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var action = lodash.find(tx.actions, {
|
||||
copayerId: fc.credentials.copayerId
|
||||
});
|
||||
|
||||
$scope.tx = txFormatService.processTx(tx);
|
||||
|
||||
if (!action && tx.status == 'pending')
|
||||
$scope.tx.pendingForUs = true;
|
||||
|
||||
$scope.updateCopayerList();
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$scope.updateCopayerList = function() {
|
||||
lodash.map($scope.copayers, function(cp) {
|
||||
lodash.each($scope.tx.actions, function(ac) {
|
||||
if (cp.id == ac.copayerId) {
|
||||
cp.action = ac.type;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function handleEncryptedWallet(cb) {
|
||||
if (!walletService.isEncrypted(fc)) return cb();
|
||||
$rootScope.$emit('Local/NeedsPassword', false, function(err, password) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, walletService.unlock(fc, password));
|
||||
});
|
||||
};
|
||||
|
||||
$scope.copyToClipboard = function(addr) {
|
||||
if (!addr) return;
|
||||
self.copyToClipboard(addr);
|
||||
};
|
||||
|
||||
$scope.close = function(txp) {
|
||||
$scope.loading = null;
|
||||
if (txp) {
|
||||
txStatus.notify(txp, function() {
|
||||
$scope.$emit('Local/TxProposalAction', txp.status == 'broadcasted');
|
||||
});
|
||||
} else {
|
||||
$timeout(function() {
|
||||
$scope.$emit('Local/TxProposalAction');
|
||||
}, 100);
|
||||
}
|
||||
$scope.cancel();
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$scope.txpDetailsModal.hide();
|
||||
};
|
||||
});
|
||||
|
|
@ -175,260 +175,21 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
|
|||
// isGlidera flag is a security measure so glidera status is not
|
||||
// only determined by the tx.message
|
||||
this.openTxpModal = function(tx, copayers, isGlidera) {
|
||||
$rootScope.modalOpened = true;
|
||||
var self = this;
|
||||
var fc = profileService.focusedClient;
|
||||
var currentSpendUnconfirmed = configWallet.spendUnconfirmed;
|
||||
var ModalInstanceCtrl = function($scope, $modalInstance) {
|
||||
$scope.paymentExpired = null;
|
||||
checkPaypro();
|
||||
$scope.error = null;
|
||||
$scope.copayers = copayers
|
||||
$scope.copayerId = fc.credentials.copayerId;
|
||||
$scope.canSign = fc.canSign() || fc.isPrivKeyExternal();
|
||||
$scope.loading = null;
|
||||
$scope.color = fc.backgroundColor;
|
||||
$scope.isShared = fc.credentials.n > 1;
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
$scope.self = self;
|
||||
$scope.tx = tx;
|
||||
$scope.copayers = copayers;
|
||||
$scope.isGlidera = isGlidera;
|
||||
$scope.error = null;
|
||||
$scope.loading = null;
|
||||
$scope.paymentExpired = null;
|
||||
$scope.currentSpendUnconfirmed = configWallet.spendUnconfirmed;
|
||||
|
||||
// ToDo: use tx.customData instead of tx.message
|
||||
if (tx.message === 'Glidera transaction' && isGlidera) {
|
||||
tx.isGlidera = true;
|
||||
if (tx.canBeRemoved) {
|
||||
tx.canBeRemoved = (Date.now() / 1000 - (tx.ts || tx.createdOn)) > GLIDERA_LOCK_TIME;
|
||||
}
|
||||
}
|
||||
$scope.tx = tx;
|
||||
$scope.currentSpendUnconfirmed = currentSpendUnconfirmed;
|
||||
|
||||
$scope.getShortNetworkName = function() {
|
||||
return fc.credentials.networkName.substring(0, 4);
|
||||
};
|
||||
|
||||
function checkPaypro() {
|
||||
if (tx.payProUrl && !isChromeApp) {
|
||||
fc.fetchPayPro({
|
||||
payProUrl: tx.payProUrl,
|
||||
}, function(err, paypro) {
|
||||
if (err) return;
|
||||
tx.paypro = paypro;
|
||||
paymentTimeControl(tx.paypro.expires);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function paymentTimeControl(expirationTime) {
|
||||
$scope.paymentExpired = false;
|
||||
setExpirationTime();
|
||||
|
||||
self.countDown = $interval(function() {
|
||||
setExpirationTime();
|
||||
}, 1000);
|
||||
|
||||
function setExpirationTime() {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
if (now > expirationTime) {
|
||||
$scope.paymentExpired = true;
|
||||
if (self.countDown) $interval.cancel(self.countDown);
|
||||
return;
|
||||
}
|
||||
var totalSecs = expirationTime - now;
|
||||
var m = Math.floor(totalSecs / 60);
|
||||
var s = totalSecs % 60;
|
||||
$scope.expires = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2);
|
||||
};
|
||||
};
|
||||
|
||||
lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy', 'transactionProposalRemoved', 'TxProposalRemoved', 'NewOutgoingTx', 'UpdateTx'], function(eventName) {
|
||||
$rootScope.$on(eventName, function() {
|
||||
fc.getTx($scope.tx.id, function(err, tx) {
|
||||
if (err) {
|
||||
if (err.message && err.message == 'TX_NOT_FOUND' &&
|
||||
(eventName == 'transactionProposalRemoved' || eventName == 'TxProposalRemoved')) {
|
||||
$scope.tx.removed = true;
|
||||
$scope.tx.canBeRemoved = false;
|
||||
$scope.tx.pendingForUs = false;
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var action = lodash.find(tx.actions, {
|
||||
copayerId: fc.credentials.copayerId
|
||||
});
|
||||
|
||||
$scope.tx = txFormatService.processTx(tx);
|
||||
|
||||
if (!action && tx.status == 'pending')
|
||||
$scope.tx.pendingForUs = true;
|
||||
|
||||
$scope.updateCopayerList();
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$scope.updateCopayerList = function() {
|
||||
lodash.map($scope.copayers, function(cp) {
|
||||
lodash.each($scope.tx.actions, function(ac) {
|
||||
if (cp.id == ac.copayerId) {
|
||||
cp.action = ac.type;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.sign = function(txp) {
|
||||
var client = profileService.focusedClient;
|
||||
$scope.error = null;
|
||||
$scope.loading = true;
|
||||
|
||||
fingerprintService.check(client, function(err) {
|
||||
if (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
return;
|
||||
}
|
||||
|
||||
handleEncryptedWallet(client, function(err) {
|
||||
if (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
return;
|
||||
}
|
||||
|
||||
walletService.signTx(client, txp, function(err, signedTxp) {
|
||||
walletService.lock(client);
|
||||
if (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
return;
|
||||
}
|
||||
|
||||
if (signedTxp.status == 'accepted') {
|
||||
walletService.broadcastTx(client, signedTxp, function(err, broadcastedTxp) {
|
||||
$scope.loading = false;
|
||||
$scope.$emit('UpdateTx');
|
||||
$modalInstance.close(broadcastedTxp);
|
||||
if (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$scope.loading = false;
|
||||
$scope.$emit('UpdateTx');
|
||||
$modalInstance.close(signedTxp);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.reject = function(txp) {
|
||||
var client = profileService.focusedClient;
|
||||
self.setOngoingProcess(gettextCatalog.getString('Rejecting payment'));
|
||||
$scope.loading = true;
|
||||
$scope.error = null;
|
||||
|
||||
$timeout(function() {
|
||||
walletService.rejectTx(client, txp, function(err, txpr) {
|
||||
self.setOngoingProcess();
|
||||
$scope.loading = false;
|
||||
if (err) {
|
||||
$scope.$emit('UpdateTx');
|
||||
$scope.error = bwsError.msg(err, gettextCatalog.getString('Could not reject payment'));
|
||||
$scope.$digest();
|
||||
} else {
|
||||
$modalInstance.close(txpr);
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
|
||||
$scope.remove = function(txp) {
|
||||
var client = profileService.focusedClient;
|
||||
self.setOngoingProcess(gettextCatalog.getString('Deleting payment'));
|
||||
$scope.loading = true;
|
||||
$scope.error = null;
|
||||
$timeout(function() {
|
||||
walletService.removeTx(client, txp, function(err) {
|
||||
self.setOngoingProcess();
|
||||
$scope.loading = false;
|
||||
|
||||
// Hacky: request tries to parse an empty response
|
||||
if (err && !(err.message && err.message.match(/Unexpected/))) {
|
||||
$scope.$emit('UpdateTx');
|
||||
$scope.error = bwsError.msg(err, gettextCatalog.getString('Could not delete payment proposal'));
|
||||
$scope.$digest();
|
||||
return;
|
||||
}
|
||||
$modalInstance.close();
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.broadcast = function(txp) {
|
||||
var client = profileService.focusedClient;
|
||||
self.setOngoingProcess(gettextCatalog.getString('Broadcasting Payment'));
|
||||
$scope.loading = true;
|
||||
$scope.error = null;
|
||||
$timeout(function() {
|
||||
walletService.broadcastTx(client, txp, function(err, txpb) {
|
||||
self.setOngoingProcess();
|
||||
$scope.loading = false;
|
||||
if (err) {
|
||||
$scope.error = bwsError.msg(err, gettextCatalog.getString('Could not broadcast payment'));
|
||||
$scope.$digest();
|
||||
return;
|
||||
}
|
||||
$modalInstance.close(txpb);
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.copyToClipboard = function(addr) {
|
||||
if (!addr) return;
|
||||
self.copyToClipboard(addr);
|
||||
};
|
||||
|
||||
$scope.cancel = lodash.debounce(function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
}, 0, 1000);
|
||||
};
|
||||
|
||||
var modalInstance = $modal.open({
|
||||
templateUrl: 'views/modals/txp-details.html',
|
||||
windowClass: animationService.modalAnimated.slideRight,
|
||||
controller: ModalInstanceCtrl,
|
||||
$ionicModal.fromTemplateUrl('views/modals/txp-details.html', {
|
||||
scope: $scope
|
||||
}).then(function(modal) {
|
||||
$scope.txpDetailsModal = modal;
|
||||
$scope.txpDetailsModal.show();
|
||||
});
|
||||
|
||||
var disableCloseModal = $rootScope.$on('closeModal', function() {
|
||||
modalInstance.dismiss('cancel');
|
||||
});
|
||||
|
||||
modalInstance.result.finally(function() {
|
||||
$rootScope.modalOpened = false;
|
||||
disableCloseModal();
|
||||
var m = angular.element(document.getElementsByClassName('reveal-modal'));
|
||||
m.addClass(animationService.modalAnimated.slideOutRight);
|
||||
});
|
||||
|
||||
modalInstance.result.then(function(txp) {
|
||||
self.setOngoingProcess();
|
||||
if (txp) {
|
||||
txStatus.notify(txp, function() {
|
||||
$scope.$emit('Local/TxProposalAction', txp.status == 'broadcasted');
|
||||
});
|
||||
} else {
|
||||
$timeout(function() {
|
||||
$scope.$emit('Local/TxProposalAction');
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
this.setAddress = function(forceNew) {
|
||||
|
|
@ -1069,6 +830,7 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
|
|||
var self = this;
|
||||
|
||||
$scope.btx = btx;
|
||||
$scope.color = profileService.focusedClient.backgroundColor;
|
||||
$scope.self = self;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/tx-details.html', {
|
||||
|
|
|
|||
|
|
@ -697,6 +697,10 @@ ul.manage li {
|
|||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.p50t {
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.p10 {
|
||||
padding: 10px;
|
||||
}
|
||||
|
|
@ -864,6 +868,7 @@ ul.manage li {
|
|||
background: #fff;
|
||||
width: 100%;
|
||||
padding-top: 60px;
|
||||
padding-bottom: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
|
@ -1975,10 +1980,8 @@ to prevent collapsing during animation*/
|
|||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding-bottom: 50px;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
background: #f6f7f9;
|
||||
}
|
||||
|
|
@ -2055,7 +2058,7 @@ body.modal-open {
|
|||
|
||||
.payment-proposal-head {
|
||||
color: #fff;
|
||||
padding: 0 10px 20px 10px;
|
||||
padding: 40px 10px 20px 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue