copay/src/js/controllers/walletHome.js

869 lines
24 KiB
JavaScript
Raw Normal View History

2015-03-06 07:00:10 -08:00
'use strict';
angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $rootScope, $timeout, $filter, $modal, $log, notification, txStatus, isCordova, profileService, lodash, configService, rateService, storageService, bitcore, isChromeApp, gettext, gettextCatalog) {
2015-03-06 07:00:10 -08:00
2015-04-23 08:27:43 -07:00
var self = this;
2015-04-21 09:06:44 -07:00
$rootScope.hideMenuBar = false;
2015-04-23 08:27:43 -07:00
$rootScope.wpInputFocused = false;
// INIT
var config = configService.getSync().wallet.settings;
this.unitToSatoshi = config.unitToSatoshi;
this.satToUnit = 1 / this.unitToSatoshi;
this.unitName = config.unitName;
this.alternativeIsoCode = config.alternativeIsoCode;
this.alternativeName = config.alternativeName;
this.alternativeAmount = 0;
this.unitDecimals = config.unitDecimals;
this.isCordova = isCordova;
this.addresses = [];
this.isMobile = isMobile.any();
this.isWindowsPhoneApp = isMobile.Windows() && isCordova;
this.blockUx = false;
this.isRateAvailable = false;
this.showScanner = false;
this.isMobile = isMobile.any();
2015-05-04 08:23:43 -07:00
this.addr = null;
2015-04-23 08:27:43 -07:00
var disableScannerListener = $rootScope.$on('dataScanned', function(event, data) {
self.setForm(data);
2015-04-28 14:11:06 -07:00
$rootScope.$emit('Local/SetTab', 'send');
2015-04-23 08:27:43 -07:00
});
var disablePaymentUriListener = $rootScope.$on('paymentUri', function(event, uri) {
$timeout(function() {
2015-04-28 14:11:06 -07:00
$rootScope.$emit('Local/SetTab', 'send');
2015-04-23 08:27:43 -07:00
self.setForm(uri);
}, 100);
});
var disableAddrListener = $rootScope.$on('Local/NeedNewAddress', function() {
2015-04-28 12:58:40 -07:00
self.setNewAddress();
2015-04-23 08:27:43 -07:00
});
2015-04-23 22:42:10 -07:00
var disableFocusListener = $rootScope.$on('Local/NewFocusedWallet', function() {
2015-04-28 12:58:40 -07:00
self.addr = null;
2015-04-23 22:42:10 -07:00
self.resetForm();
});
2015-04-23 11:19:30 -07:00
2015-04-28 15:26:22 -07:00
var disableOnlineListener = $rootScope.$on('Local/Online', function() {
// This is needed then the apps go to sleep
self.bindTouchDown();
2015-04-28 15:26:22 -07:00
});
2015-04-28 14:00:49 -07:00
var disableResumeListener = $rootScope.$on('Local/Resume', function() {
2015-04-28 15:26:22 -07:00
// This is needed then the apps go to sleep
self.bindTouchDown();
2015-04-28 14:00:49 -07:00
});
2015-04-28 15:26:22 -07:00
2015-04-23 22:42:10 -07:00
var disableTabListener = $rootScope.$on('Local/TabChanged', function(e, tab) {
2015-04-28 12:58:40 -07:00
// This will slow down switch, do not add things here!
2015-04-23 22:42:10 -07:00
switch (tab) {
2015-04-23 11:19:30 -07:00
case 'receive':
2015-04-28 12:58:40 -07:00
// just to be sure we have an address
self.setAddress();
2015-04-23 11:19:30 -07:00
break;
2015-04-28 12:58:40 -07:00
case 'send':
self.resetError();
2015-04-23 11:19:30 -07:00
};
});
2015-04-23 08:27:43 -07:00
$scope.$on('$destroy', function() {
disableAddrListener();
disableScannerListener();
disablePaymentUriListener();
2015-04-23 11:19:30 -07:00
disableTabListener();
2015-04-23 22:42:10 -07:00
disableFocusListener();
2015-04-28 14:00:49 -07:00
disableResumeListener();
2015-04-28 15:26:22 -07:00
disableOnlineListener();
2015-04-23 08:27:43 -07:00
$rootScope.hideMenuBar = false;
});
rateService.whenAvailable(function() {
self.isRateAvailable = true;
$rootScope.$digest();
});
// walletHome
2015-03-06 07:00:10 -08:00
$scope.openCopayersModal = function(copayers, copayerId) {
2015-04-16 07:35:45 -07:00
var fc = profileService.focusedClient;
2015-05-07 15:02:38 -07:00
2015-03-06 07:00:10 -08:00
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.copayers = copayers;
$scope.copayerId = copayerId;
2015-04-16 07:35:45 -07:00
$scope.color = fc.backgroundColor;
2015-05-07 15:02:38 -07:00
$scope.cancel = function() {
2015-03-06 07:00:10 -08:00
$modalInstance.dismiss('cancel');
};
};
2015-05-07 15:02:38 -07:00
var modalInstance = $modal.open({
2015-03-06 07:00:10 -08:00
templateUrl: 'views/modals/copayers.html',
2015-05-07 15:02:38 -07:00
windowClass: 'full animated slideInUp',
2015-03-06 07:00:10 -08:00
controller: ModalInstanceCtrl,
});
2015-05-07 15:02:38 -07:00
modalInstance.result.finally(function() {
var m = angular.element(document.getElementsByClassName('reveal-modal'));
m.addClass('slideOutDown');
});
2015-03-06 07:00:10 -08:00
};
2015-05-06 07:16:19 -07:00
this.openTxpModal = function(tx, copayers) {
2015-03-06 07:00:10 -08:00
var fc = profileService.focusedClient;
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.error = null;
$scope.tx = tx;
$scope.amountStr = tx.amountStr;
$scope.alternativeAmountStr = tx.alternativeAmountStr;
2015-03-06 07:00:10 -08:00
$scope.copayers = copayers
$scope.loading = null;
$scope.color = fc.backgroundColor;
$scope.getShortNetworkName = function() {
return fc.credentials.networkName.substring(0, 4);
};
2015-04-17 14:10:22 -07:00
lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy', 'transactionProposalRemoved', 'TxProposalRemoved', 'NewOutgoingTx'], function(eventName) {
2015-03-06 07:00:10 -08:00
$rootScope.$on(eventName, function() {
fc.getTx($scope.tx.id, function(err, tx) {
if (err) {
if (err.code && err.code == 'BADREQUEST' &&
(eventName == 'transactionProposalRemoved' || eventName == 'TxProposalRemoved')) {
$scope.tx.removed = true;
$scope.tx.couldRemove = false;
$scope.tx.pendingForUs = false;
$scope.$apply();
return;
}
return;
}
var action = lodash.find(tx.actions, {
copayerId: fc.credentials.copayerId
});
$scope.tx = 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 fc = profileService.focusedClient;
if (fc.isPrivKeyEncrypted()) {
profileService.unlockFC(function(err) {
if (err) {
$scope.error = err;
return;
}
return $scope.sign(txp);
});
return;
};
self.setOngoingProcess(gettext('Signing transaction'));
2015-03-06 07:00:10 -08:00
$scope.loading = true;
$scope.error = null;
$timeout(function() {
fc.signTxProposal(txp, function(err, txpsi) {
profileService.lockFC();
self.setOngoingProcess();
2015-03-06 07:00:10 -08:00
if (err) {
$scope.loading = false;
$scope.error = err.message || gettext('Transaction not signed. Please try again.');
2015-03-06 07:00:10 -08:00
$scope.$digest();
} else {
//if txp has required signatures then broadcast it
var txpHasRequiredSignatures = txpsi.status == 'accepted';
if (txpHasRequiredSignatures) {
self.setOngoingProcess(gettext('Broadcasting transaction'));
$scope.loading = true;
2015-03-06 07:00:10 -08:00
fc.broadcastTxProposal(txpsi, function(err, txpsb) {
self.setOngoingProcess();
$scope.loading = false;
2015-03-06 07:00:10 -08:00
if (err) {
$scope.error = gettext('Transaction not broadcasted. Please try again.');
2015-03-06 07:00:10 -08:00
$scope.$digest();
} else {
$modalInstance.close(txpsb);
}
});
} else {
$scope.loading = false;
2015-03-06 07:00:10 -08:00
$modalInstance.close(txpsi);
}
}
});
}, 100);
};
$scope.reject = function(txp) {
self.setOngoingProcess(gettext('Rejecting transaction'));
2015-03-06 07:00:10 -08:00
$scope.loading = true;
$scope.error = null;
$timeout(function() {
fc.rejectTxProposal(txp, null, function(err, txpr) {
self.setOngoingProcess();
2015-03-06 07:00:10 -08:00
$scope.loading = false;
if (err) {
$scope.error = err.message || gettext('Transaction not rejected. Please try again.');
2015-03-06 07:00:10 -08:00
$scope.$digest();
} else {
$modalInstance.close(txpr);
}
});
}, 100);
};
$scope.remove = function(txp) {
self.setOngoingProcess(gettext('Deleting transaction'));
2015-03-06 07:00:10 -08:00
$scope.loading = true;
$scope.error = null;
$timeout(function() {
fc.removeTxProposal(txp, function(err, txpb) {
self.setOngoingProcess();
2015-03-06 07:00:10 -08:00
$scope.loading = false;
// Hacky: request tries to parse an empty response
2015-04-21 09:06:44 -07:00
if (err && !(err.message && err.message.match(/Unexpected/))) {
$scope.error = err.message || gettext('Transaction could not be deleted. Please try again.');
2015-03-06 07:00:10 -08:00
$scope.$digest();
return;
2015-04-21 09:06:44 -07:00
}
2015-03-06 07:00:10 -08:00
$modalInstance.close();
});
}, 100);
};
$scope.broadcast = function(txp) {
self.setOngoingProcess(gettext('Broadcasting transaction'));
2015-03-06 07:00:10 -08:00
$scope.loading = true;
$scope.error = null;
$timeout(function() {
fc.broadcastTxProposal(txp, function(err, txpb) {
self.setOngoingProcess();
2015-03-06 07:00:10 -08:00
$scope.loading = false;
if (err) {
$scope.error = err.message || gettext('Transaction not sent. Please try again.');
2015-03-06 07:00:10 -08:00
$scope.$digest();
} else {
$modalInstance.close(txpb);
}
});
}, 100);
};
2015-04-26 22:31:07 -07:00
$scope.copyAddress = function(addr) {
if (!addr) return;
self.copyAddress(addr);
};
2015-03-06 07:00:10 -08:00
$scope.cancel = function() {
2015-04-21 22:48:00 -07:00
$modalInstance.dismiss('cancel');
2015-03-06 07:00:10 -08:00
};
};
var modalInstance = $modal.open({
templateUrl: 'views/modals/txp-details.html',
2015-05-07 15:02:38 -07:00
windowClass: 'full animated slideInUp',
2015-03-06 07:00:10 -08:00
controller: ModalInstanceCtrl,
});
2015-05-07 15:02:38 -07:00
modalInstance.result.finally(function() {
var m = angular.element(document.getElementsByClassName('reveal-modal'));
m.addClass('slideOutDown');
});
2015-03-06 07:00:10 -08:00
modalInstance.result.then(function(txp) {
if (txp) {
2015-04-28 11:17:13 -07:00
self.setOngoingProcess();
2015-05-08 07:38:34 -07:00
txStatus.notify(txp, function() {
$scope.$emit('Local/TxProposalAction');
});
2015-03-06 07:00:10 -08:00
}
});
};
2015-04-23 08:27:43 -07:00
// Receive
2015-04-28 12:58:40 -07:00
this.setNewAddress = function() {
2015-04-23 08:27:43 -07:00
var fc = profileService.focusedClient;
2015-04-26 14:41:21 -07:00
self.generatingAddress = true;
2015-04-23 08:27:43 -07:00
fc.createAddress(function(err, addr) {
self.generatingAddress = false;
2015-04-23 08:27:43 -07:00
if (err) {
if (err.error.match(/locked/gi)) {
$log.debug(err.error);
$timeout(function() {
self.setNewAddress();
}, 5000);
}
else {
$log.debug('Creating address ERROR:', err);
$scope.$emit('Local/ClientError', err);
$scope.$digest();
}
2015-04-26 14:41:21 -07:00
return;
2015-04-23 08:27:43 -07:00
}
2015-04-26 14:41:21 -07:00
self.addr = addr.address;
storageService.storeLastAddress(fc.credentials.walletId, addr.address, function() {
self.generatingAddress = false;
$scope.$digest();
});
2015-04-23 08:27:43 -07:00
});
};
2015-04-28 12:58:40 -07:00
this.setAddress = function() {
if (self.addr)
return;
2015-04-23 08:27:43 -07:00
var fc = profileService.focusedClient;
$timeout(function() {
storageService.getLastAddress(fc.credentials.walletId, function(err, addr) {
2015-04-26 14:43:37 -07:00
if (addr) {
2015-04-23 08:27:43 -07:00
self.addr = addr;
2015-04-28 12:58:40 -07:00
$scope.$digest();
2015-04-23 08:27:43 -07:00
} else {
2015-04-28 12:58:40 -07:00
self.setNewAddress();
2015-04-23 08:27:43 -07:00
}
});
});
};
this.copyAddress = function(addr) {
if (isCordova) {
window.cordova.plugins.clipboard.copy('bitcoin:' + addr);
window.plugins.toast.showShortCenter('Copied to clipboard');
}
};
this.shareAddress = function(addr) {
if (isCordova) {
if (isMobile.Android() || isMobile.Windows()) {
window.ignoreMobilePause = true;
}
window.plugins.socialsharing.share('bitcoin:' + addr, null, null, null);
}
};
// Send
2015-04-28 08:06:04 -07:00
this.canShowAlternative = function() {
return $scope.showAlternative;
};
this.showAlternative = function() {
$scope.showAlternative = true;
};
this.hideAlternative = function() {
$scope.showAlternative = false;
};
2015-04-23 08:27:43 -07:00
this.resetError = function() {
this.error = this.success = null;
};
2015-04-28 12:08:43 -07:00
this.bindTouchDown = function(tries) {
var self = this;
tries = tries || 0;
if (tries > 5) return;
var e = document.getElementById('menu-walletHome');
2015-04-28 16:13:28 -07:00
if (!e) return $timeout(function() {
2015-04-28 12:08:43 -07:00
self.bindTouchDown(++tries);
}, 500);
// on touchdown elements
$log.debug('Binding touchstart elements...');
2015-04-29 08:08:16 -07:00
['hamburger', 'menu-walletHome', 'menu-send', 'menu-receive', 'menu-history'].forEach(function(id) {
2015-04-28 12:08:43 -07:00
var e = document.getElementById(id);
if (e) e.addEventListener('touchstart', function() {
try {
event.preventDefault();
} catch (e) {};
2015-04-28 12:08:43 -07:00
angular.element(e).triggerHandler('click');
}, true);
2015-04-28 12:08:43 -07:00
});
}
2015-04-23 08:27:43 -07:00
2015-04-28 12:08:43 -07:00
this.hideMenuBar = lodash.debounce(function(hide) {
2015-04-23 08:27:43 -07:00
if (hide) {
$rootScope.hideMenuBar = true;
2015-04-28 12:08:43 -07:00
this.bindTouchDown();
2015-04-23 08:27:43 -07:00
} else {
$rootScope.hideMenuBar = false;
}
$rootScope.$digest();
}, 100);
this.formFocus = function(what) {
if (isCordova && !this.isWindowsPhoneApp) {
2015-04-28 12:08:43 -07:00
this.hideMenuBar(what);
2015-04-23 08:27:43 -07:00
}
if (!this.isWindowsPhoneApp) return
if (!what) {
this.hideAddress = false;
this.hideAmount = false;
} else {
if (what == 'amount') {
this.hideAddress = true;
} else if (what == 'msg') {
this.hideAddress = true;
this.hideAmount = true;
}
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
2015-04-28 12:58:40 -07:00
this.setSendFormInputs = function() {
2015-04-23 08:27:43 -07:00
var unitToSat = this.unitToSatoshi;
var satToUnit = 1 / unitToSat;
/**
* Setting the two related amounts as properties prevents an infinite
* recursion for watches while preserving the original angular updates
*
*/
Object.defineProperty($scope,
"_alternative", {
get: function() {
return $scope.__alternative;
},
set: function(newValue) {
$scope.__alternative = newValue;
if (typeof(newValue) === 'number' && self.isRateAvailable) {
$scope._amount = parseFloat((rateService.fromFiat(newValue, self.alternativeIsoCode) * satToUnit).toFixed(self.unitDecimals), 10);
}
},
enumerable: true,
configurable: true
});
Object.defineProperty($scope,
"_amount", {
get: function() {
return $scope.__amount;
},
set: function(newValue) {
$scope.__amount = newValue;
if (typeof(newValue) === 'number' && self.isRateAvailable) {
$scope.__alternative = parseFloat((rateService.toFiat(newValue * self.unitToSatoshi, self.alternativeIsoCode)).toFixed(2), 10);
} else {
$scope.__alternative = 0;
}
self.alternativeAmount = $scope.__alternative;
self.resetError();
},
enumerable: true,
configurable: true
});
Object.defineProperty($scope,
"_address", {
get: function() {
return $scope.__address;
},
set: function(newValue) {
$scope.__address = self.onAddressChange(newValue);
},
enumerable: true,
configurable: true
});
};
this.setError = function(err) {
2015-04-23 11:23:21 -07:00
var fc = profileService.focusedClient;
2015-04-23 08:27:43 -07:00
$log.warn(err);
var errMessage = 'The transaction' + (fc.credentials.m > 1 ? ' proposal' : '') +
' could not be created: ' + (err.message ? err.message : err);
this.error = errMessage;
$timeout(function() {
$scope.$digest();
}, 1);
};
this.setOngoingProcess = function(name) {
var self = this;
2015-04-23 22:42:10 -07:00
self.blockUx = !!name;
if (isCordova) {
if (name) {
2015-04-28 13:49:09 -07:00
window.plugins.spinnerDialog.hide();
2015-04-23 22:42:10 -07:00
window.plugins.spinnerDialog.show(null, name + '...', true);
} else {
window.plugins.spinnerDialog.hide();
}
} else {
2015-04-28 13:19:22 -07:00
self.onGoingProcess = name;
2015-04-28 13:28:49 -07:00
$timeout(function() {
$rootScope.$apply();
});
2015-04-28 13:19:22 -07:00
};
2015-04-23 08:27:43 -07:00
};
2015-04-23 22:42:10 -07:00
this.submitForm = function() {
2015-04-23 11:23:21 -07:00
var fc = profileService.focusedClient;
2015-04-23 08:27:43 -07:00
var unitToSat = this.unitToSatoshi;
2015-04-23 22:42:10 -07:00
var form = $scope.sendForm;
2015-04-23 08:27:43 -07:00
if (form.$invalid) {
this.error = gettext('Unable to send transaction proposal');
2015-04-23 08:27:43 -07:00
return;
}
if (fc.isPrivKeyEncrypted()) {
profileService.unlockFC(function(err) {
if (err) return self.setError(err);
2015-04-23 22:42:10 -07:00
return self.submitForm();
2015-04-23 08:27:43 -07:00
});
return;
};
self.setOngoingProcess(gettext('Creating transaction'));
2015-04-23 08:27:43 -07:00
$timeout(function() {
var comment = form.comment.$modelValue;
var paypro = self._paypro;
var address, amount;
address = form.address.$modelValue;
amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0));
fc.sendTxProposal({
toAddress: address,
amount: amount,
message: comment,
payProUrl: paypro ? paypro.url : null,
}, function(err, txp) {
if (err) {
2015-04-26 22:38:48 -07:00
self.setOngoingProcess();
2015-04-23 08:27:43 -07:00
profileService.lockFC();
return self.setError(err);
}
self.signAndBroadcast(txp, function(err) {
if (err) {
2015-04-26 22:38:48 -07:00
self.setOngoingProcess();
2015-04-23 08:27:43 -07:00
return self.setError(err);
}
2015-04-26 22:07:26 -07:00
2015-04-23 22:42:10 -07:00
self.resetForm();
2015-04-23 08:27:43 -07:00
});
});
}, 100);
};
this.signAndBroadcast = function(txp, cb) {
2015-04-23 11:23:21 -07:00
var fc = profileService.focusedClient;
self.setOngoingProcess(gettext('Signing transaction'));
2015-04-23 08:27:43 -07:00
fc.signTxProposal(txp, function(err, signedTx) {
profileService.lockFC();
2015-04-26 14:41:21 -07:00
if (err) {
2015-04-26 22:38:48 -07:00
self.setOngoingProcess();
return cb(err);
}
2015-04-23 08:27:43 -07:00
if (signedTx.status == 'accepted') {
self.setOngoingProcess(gettext('Broadcasting transaction'));
2015-04-23 08:27:43 -07:00
fc.broadcastTxProposal(signedTx, function(err, btx) {
2015-04-28 13:28:49 -07:00
self.setOngoingProcess();
2015-04-23 08:27:43 -07:00
if (err) {
$scope.error = gettext('Transaction not broadcasted. Please try again.');
2015-04-23 08:27:43 -07:00
$scope.$digest();
2015-04-28 13:28:49 -07:00
return cb(err);
2015-04-23 08:27:43 -07:00
}
2015-04-26 22:38:48 -07:00
txStatus.notify(btx, function() {
2015-05-08 07:38:34 -07:00
$scope.$emit('Local/TxProposalAction');
2015-04-26 22:38:48 -07:00
return cb();
});
2015-04-23 08:27:43 -07:00
});
} else {
2015-04-28 11:17:13 -07:00
self.setOngoingProcess();
2015-04-26 22:38:48 -07:00
txStatus.notify(signedTx, function() {
2015-05-08 07:38:34 -07:00
$scope.$emit('Local/TxProposalAction');
2015-04-26 22:38:48 -07:00
return cb();
});
2015-04-23 08:27:43 -07:00
}
});
};
this.setForm = function(to, amount, comment) {
var form = $scope.sendForm;
if (to) {
form.address.$setViewValue(to);
form.address.$isValid = true;
form.address.$render();
this.lockAddress = true;
}
if (amount) {
form.amount.$setViewValue("" + amount);
form.amount.$isValid = true;
form.amount.$render();
this.lockAmount = true;
}
if (comment) {
form.comment.$setViewValue(comment);
form.comment.$isValid = true;
form.comment.$render();
}
};
2015-04-23 22:42:10 -07:00
this.resetForm = function() {
2015-04-23 08:27:43 -07:00
this.resetError();
this._paypro = null;
this.lockAddress = false;
this.lockAmount = false;
this._amount = this._address = null;
2015-04-23 22:42:10 -07:00
var form = $scope.sendForm;
2015-04-23 08:27:43 -07:00
if (form && form.amount) {
form.amount.$pristine = true;
form.amount.$setViewValue('');
form.amount.$render();
form.comment.$setViewValue('');
form.comment.$render();
form.$setPristine();
if (form.address) {
form.address.$pristine = true;
form.address.$setViewValue('');
form.address.$render();
}
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
this.openPPModal = function(paypro) {
var ModalInstanceCtrl = function($scope, $modalInstance) {
2015-04-23 11:23:21 -07:00
var fc = profileService.focusedClient;
2015-04-23 08:27:43 -07:00
var satToUnit = 1 / self.unitToSatoshi;
$scope.paypro = paypro;
$scope.alternative = self.alternativeAmount;
$scope.alternativeIsoCode = self.alternativeIsoCode;
$scope.isRateAvailable = self.isRateAvailable;
$scope.unitTotal = (paypro.amount * satToUnit).toFixed(self.unitDecimals);
$scope.unitName = self.unitName;
$scope.color = fc.backgroundColor;
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
2015-05-07 15:02:38 -07:00
var modalInstance = $modal.open({
2015-04-23 08:27:43 -07:00
templateUrl: 'views/modals/paypro.html',
2015-05-07 15:02:38 -07:00
windowClass: 'full animated slideInUp',
2015-04-23 08:27:43 -07:00
controller: ModalInstanceCtrl,
});
2015-05-07 15:02:38 -07:00
modalInstance.result.finally(function() {
var m = angular.element(document.getElementsByClassName('reveal-modal'));
m.addClass('slideOutDown');
});
2015-04-23 08:27:43 -07:00
};
2015-04-23 22:42:10 -07:00
this.setFromPayPro = function(uri) {
2015-04-23 11:23:21 -07:00
var fc = profileService.focusedClient;
2015-04-23 08:27:43 -07:00
if (isChromeApp) {
this.error = gettext('Payment Protocol not supported on Chrome App');
2015-04-23 08:27:43 -07:00
return;
}
var satToUnit = 1 / this.unitToSatoshi;
var self = this;
/// Get information of payment if using Payment Protocol
self.setOngoingProcess(gettext('Fetching Payment Information'));
2015-04-23 08:27:43 -07:00
$log.debug('Fetch PayPro Request...', uri);
$timeout(function() {
fc.fetchPayPro({
payProUrl: uri,
}, function(err, paypro) {
2015-04-23 22:42:10 -07:00
self.setOngoingProcess();
2015-04-23 08:27:43 -07:00
if (err) {
$log.warn(err);
2015-04-23 22:42:10 -07:00
self.resetForm();
2015-04-23 08:27:43 -07:00
var msg = err.toString();
if (msg.match('HTTP')) {
msg = gettext('Could not fetch payment information');
2015-04-23 08:27:43 -07:00
}
self.error = msg;
} else {
self._paypro = paypro;
self.setForm(paypro.toAddress, (paypro.amount * satToUnit).toFixed(self.unitDecimals),
paypro.memo);
}
});
}, 1);
};
this.setFromUri = function(uri) {
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 = sanitizeUri(uri);
if (!bitcore.URI.isValid(uri)) {
return uri;
}
var parsed = new bitcore.URI(uri);
var addr = parsed.address.toString();
var message = parsed.message;
if (parsed.r)
return this.setFromPayPro(parsed.r);
var amount = parsed.amount ?
(parsed.amount.toFixed(0) * satToUnit).toFixed(this.unitDecimals) : 0;
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._addRates = function(txs, cb) {
if (!txs || txs.length == 0) return cb();
var index = lodash.groupBy(txs, 'rateTs');
rateService.getHistoricRates(config.alternativeIsoCode, lodash.keys(index), function(err, res) {
if (err || !res) return cb(err);
lodash.each(res, function(r) {
lodash.each(index[r.ts], function(tx) {
var alternativeAmount = (r.rate != null ? tx.amount * rateService.SAT_TO_BTC * r.rate : null);
tx.alternativeAmount = alternativeAmount ? $filter('noFractionNumber')(alternativeAmount, 2) : null;
});
});
return cb();
});
};
this.openTxModal = function(btx) {
var self = this;
var fc = profileService.focusedClient;
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.btx = btx;
$scope.settings = config;
$scope.color = fc.backgroundColor;
$scope.getAmount = function(amount) {
return self.getAmount(amount);
};
$scope.getUnitName = function() {
return self.getUnitName();
};
$scope.getShortNetworkName = function() {
var n = fc.credentials.network;
return n.substring(0, 4);
};
2015-04-26 22:31:07 -07:00
$scope.copyAddress = function(addr) {
if (!addr) return;
self.copyAddress(addr);
};
2015-04-23 08:27:43 -07:00
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
2015-05-07 15:02:38 -07:00
var modalInstance = $modal.open({
2015-04-23 08:27:43 -07:00
templateUrl: 'views/modals/tx-details.html',
2015-05-07 15:02:38 -07:00
windowClass: 'full animated slideInUp',
2015-04-23 08:27:43 -07:00
controller: ModalInstanceCtrl,
});
2015-05-07 15:02:38 -07:00
modalInstance.result.finally(function() {
var m = angular.element(document.getElementsByClassName('reveal-modal'));
m.addClass('slideOutDown');
});
2015-04-23 08:27:43 -07:00
};
this.hasAction = function(actions, action) {
return actions.hasOwnProperty('create');
};
2015-04-28 12:08:43 -07:00
// Startup events
this.bindTouchDown();
2015-04-28 12:58:40 -07:00
this.setAddress();
this.setSendFormInputs();
2015-04-28 12:08:43 -07:00
2015-03-06 07:00:10 -08:00
});