diff --git a/public/img/qr.png b/public/img/qr.png new file mode 100644 index 000000000..a5e5212b7 Binary files /dev/null and b/public/img/qr.png differ diff --git a/public/views/walletHome.html b/public/views/walletHome.html index 2691e0fc9..6f9a6c7c2 100644 --- a/public/views/walletHome.html +++ b/public/views/walletHome.html @@ -185,16 +185,36 @@
-
+

My Bitcoin address

+

{{home.addr}}

+
+
+
+
+
+
+
+
+
+
+
+
+ +
+

...

+
+
+
+
@@ -207,10 +227,10 @@
-
+
diff --git a/src/css/main.css b/src/css/main.css index d84d5129c..641b4ddf4 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -1145,11 +1145,13 @@ input.ng-invalid-match, input.ng-invalid-match:focus { /*/////////////////// SPINNER ////////////////////*/ -#history .spinner { +#history .spinner, #receive .spinner { height: 46px; } -#history .spinner > div { +#history .spinner > div, +#receive .spinner > div +{ background-color: #7A8C9E; } diff --git a/src/js/controllers/copayers.js b/src/js/controllers/copayers.js index 816a5caa0..e045453c8 100644 --- a/src/js/controllers/copayers.js +++ b/src/js/controllers/copayers.js @@ -95,8 +95,8 @@ angular.module('copayApp.controllers').controller('copayersController', if (isMobile.Android() || isMobile.Windows()) { window.ignoreMobilePause = true; } - var message = 'Join my Copay wallet. Here is the invitation code ' + secret + ' You can download Copay for your phone or desktop at https://copay.io'; - window.plugins.socialsharing.share(message, null, null, null); + var message = 'Join my Copay wallet. Here is the invitation code: ' + secret + ' You can download Copay for your phone or desktop at https://copay.io'; + window.plugins.socialsharing.share(message, 'Invitation to share a Copay Wallet', null, null); } }; diff --git a/src/js/controllers/history.js b/src/js/controllers/history.js deleted file mode 100644 index 9f9275abe..000000000 --- a/src/js/controllers/history.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('historyController', - function($scope, $rootScope, $filter, $timeout, $modal, $log, profileService, notification, go, configService, rateService, lodash) { - - }); diff --git a/src/js/controllers/receive.js b/src/js/controllers/receive.js deleted file mode 100644 index dd82b60f6..000000000 --- a/src/js/controllers/receive.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('receiveController', - function($rootScope, $scope, $timeout, $modal, $log, isCordova, isMobile, profileService, storageService) { - var self = this; - - this.isCordova = isCordova; - self.addresses = []; - - var newAddrListener = $rootScope.$on('Local/NeedNewAddress', function() { - self.getAddress(); - }); - $scope.$on('$destroy', newAddrListener); - - this.newAddress = function() { - var fc = profileService.focusedClient; - self.generatingAddress = true; - self.error = null; - fc.createAddress(function(err, addr) { - self.generatingAddress = false; - if (err) { - $log.debug('Creating address ERROR:', err); - $scope.$emit('Local/ClientError', err); - self.error='Could not generate address'; - } else { - self.addr = addr.address; - storageService.storeLastAddress(fc.credentials.walletId, addr.address, function() {}); - } - $scope.$digest(); - }); - }; - - this.getAddress = function() { - var fc = profileService.focusedClient; - $timeout(function() { - storageService.getLastAddress(fc.credentials.walletId, function(err, addr) { - if (addr) { - self.addr = addr; - } else { - self.newAddress(); - } - }); - }); - }; - - 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); - } - }; - - } -); diff --git a/src/js/controllers/send.js b/src/js/controllers/send.js deleted file mode 100644 index 8a38e65a5..000000000 --- a/src/js/controllers/send.js +++ /dev/null @@ -1,433 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('sendController', - function($rootScope, $scope, $window, $timeout, $modal, $filter, $log, notification, isMobile, txStatus, isCordova, bitcore, profileService, configService, rateService, isChromeApp, lodash) { - var fc = profileService.focusedClient; - var self = this; - - this.resetError = function() { - this.error = this.success = null; - }; - - this.init = function() { - this.isMobile = isMobile.any(); - this.isWindowsPhoneApp = isMobile.Windows() && isCordova; - $rootScope.wpInputFocused = false; - - $rootScope.title = fc.credentials.m > 1 ? 'Send Proposal' : 'Send'; - this.blockUx = false; - this.resetError(); - - this.isRateAvailable = false; - this.showScanner = false; - this.isMobile = isMobile.any(); - - var paymentUri = $rootScope.$on('paymentUri', function(event, uri) { - $timeout(function() { - self.setForm(uri); - }, 100); - }); - - var config = configService.getSync().wallet.settings; - this.alternativeName = config.alternativeName; - this.alternativeAmount = 0; - this.alternativeIsoCode = config.alternativeIsoCode; - this.unitToSatoshi = config.unitToSatoshi; - this.unitDecimals = config.unitDecimals; - this.unitName = config.unitName; - - - rateService.whenAvailable(function() { - self.isRateAvailable = true; - $rootScope.$digest(); - }); - - - var openScannerCordova = $rootScope.$on('dataScanned', function(event, data) { - self.setForm(data); - }); - - $scope.$on('$destroy', function() { - $rootScope.hideMenuBar = false; - openScannerCordova(); - paymentUri(); - }); - - this.setInputs(); - }; - - var hideMenuBar = lodash.debounce(function(hide) { - if (hide) { - $rootScope.hideMenuBar = true; - } else { - $rootScope.hideMenuBar = false; - } - $rootScope.$digest(); - }, 100); - - - this.formFocus = function(what) { - if (isCordova) { - hideMenuBar(what); - } - 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); - }; - - this.setInputs = function() { - 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) { - $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; - $timeout(function() { - self.onGoingProcess = name; - $rootScope.$apply(); - }) - }; - - this.submitForm = function(form) { - var unitToSat = this.unitToSatoshi; - - if (form.$invalid) { - this.error = 'Unable to send transaction proposal'; - return; - } - - if (fc.isPrivKeyEncrypted()) { - profileService.unlockFC(function(err) { - if (err) return self.setError(err); - return self.submitForm(form); - }); - return; - }; - - self.blockUx = true; - self.setOngoingProcess('Sending'); - - if (isCordova) { - window.plugins.spinnerDialog.show(null, 'Creating transaction...', true); - } - - $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) { - self.setOngoingProcess(); - if (err) { - profileService.lockFC(); - if (isCordova) { - window.plugins.spinnerDialog.hide(); - } - self.blockUx = false; - return self.setError(err); - } - - self.signAndBroadcast(txp, function(err) { - self.setOngoingProcess(); - if (isCordova) { - window.plugins.spinnerDialog.hide(); - } - self.blockUx = false; - if (err) { - profileService.lockFC(); - return self.setError(err); - } - self.resetForm(form); - }); - }); - }, 100); - }; - - - this.signAndBroadcast = function(txp, cb) { - self.setOngoingProcess('Signing'); - fc.signTxProposal(txp, function(err, signedTx) { - profileService.lockFC(); - self.setOngoingProcess(); - - if (err) return cb(err); - - if (signedTx.status == 'accepted') { - self.setOngoingProcess('Broadcasting'); - fc.broadcastTxProposal(signedTx, function(err, btx) { - self.setOngoingProcess(); - if (err) { - $scope.error = 'Transaction not broadcasted. Please try again.'; - $scope.$digest(); - } else { - txStatus.notify(btx); - $scope.$emit('Local/TxProposalAction'); - } - return cb(); - }); - } else { - txStatus.notify(signedTx); - $scope.$emit('Local/TxProposalAction'); - return cb(); - } - }); - }; - - this.setTopAmount = function() { - throw new Error('todo: setTopAmount'); - var form = $scope.sendForm; - if (form) { - form.amount.$setViewValue(w.balanceInfo.topAmount); - form.amount.$render(); - form.amount.$isValid = true; - } - }; - - 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(); - } - }; - - - - this.resetForm = function(form) { - this.resetError(); - this.fetchingURL = null; - this._paypro = null; - - this.lockAddress = false; - this.lockAmount = false; - - this._amount = this._address = null; - - 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) { - 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'); - }; - }; - $modal.open({ - templateUrl: 'views/modals/paypro.html', - windowClass: 'full', - controller: ModalInstanceCtrl, - }); - }; - - this.setFromPayPro = function(uri, form) { - if (isChromeApp) { - this.error = 'Payment Protocol not supported on Chrome App'; - return; - } - - var satToUnit = 1 / this.unitToSatoshi; - this.fetchingURL = uri; - this.blockUx = true; - var self = this; - - $log.debug('Fetch PayPro Request...', uri); - $timeout(function() { - fc.fetchPayPro({ - payProUrl: uri, - }, function(err, paypro) { - $log.debug(paypro); - self.blockUx = false; - self.fetchingURL = null; - - if (err) { - $log.warn(err); - self.resetForm(form); - var msg = err.toString(); - if (msg.match('HTTP')) { - msg = 'Could not fetch payment information'; - } - 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; - } - }; - }); diff --git a/src/js/controllers/walletHome.js b/src/js/controllers/walletHome.js index d32fb1ede..e01f78f91 100644 --- a/src/js/controllers/walletHome.js +++ b/src/js/controllers/walletHome.js @@ -272,17 +272,21 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi this.newAddress = function() { var fc = profileService.focusedClient; - self.setOngoingProcess('Generating Address'); + self.generatingAddress = true; fc.createAddress(function(err, addr) { - self.setOngoingProcess(); if (err) { $log.debug('Creating address ERROR:', err); $scope.$emit('Local/ClientError', err); - } else { - self.addr = addr.address; - storageService.storeLastAddress(fc.credentials.walletId, addr.address, function() {}); + self.generatingAddress = false; + $scope.$digest(); + return; } - $scope.$digest(); + self.addr = addr.address; + storageService.storeLastAddress(fc.credentials.walletId, addr.address, function() { + + self.generatingAddress = false; + $scope.$digest(); + }); }); }; @@ -500,7 +504,7 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi profileService.lockFC(); self.setOngoingProcess(); - if (err) { + if (err) { return cb(err); }