diff --git a/src/js/controllers/addressbookView.js b/src/js/controllers/addressbookView.js
index 89c1cd924..16df9e559 100644
--- a/src/js/controllers/addressbookView.js
+++ b/src/js/controllers/addressbookView.js
@@ -21,28 +21,14 @@ angular.module('copayApp.controllers').controller('addressbookViewController', f
});
$scope.sendTo = function() {
- $ionicHistory.removeBackView();
- sendFlowService.clear();
- $state.go('tabs.send');
- $timeout(function() {
- var to = '';
- if ($scope.addressbookEntry.coin == 'bch') {
- var a = 'bitcoincash:' + $scope.addressbookEntry.address;
- to = bitcoinCashJsService.readAddress(a).legacy;
- } else {
- to = $scope.addressbookEntry.address;
- }
+ var stateParams = {
+ data: $scope.addressbookEntry.address,
+ toName: $scope.addressbookEntry.name,
+ toEmail: $scope.addressbookEntry.email,
+ coin: $scope.addressbookEntry.coin
+ };
- var stateParams = {
- toAddress: to,
- toName: $scope.addressbookEntry.name,
- toEmail: $scope.addressbookEntry.email,
- coin: $scope.addressbookEntry.coin
- };
-
- sendFlowService.pushState(stateParams);
- $state.transitionTo('tabs.send.origin');
- }, 100);
+ sendFlowService.start(stateParams);
};
$scope.remove = function(addressbookEntry) {
diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js
index f796f9559..e861b36ff 100644
--- a/src/js/controllers/amount.js
+++ b/src/js/controllers/amount.js
@@ -68,13 +68,14 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
function onBeforeEnter(event, data) {
if (data.direction == "back") {
- sendFlowService.popState();
+ sendFlowService.state.pop();
}
- console.log('amount onBeforeEnter after back sendflow ', sendFlowService.state);
initCurrencies();
- passthroughParams = sendFlowService.getStateClone();
+ passthroughParams = sendFlowService.state.getClone();
+
+ console.log('amount onBeforeEnter after back sendflow ', passthroughParams);
vm.fromWalletId = passthroughParams.fromWalletId;
vm.toWalletId = passthroughParams.toWalletId;
@@ -214,7 +215,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
}
function goBack() {
- $ionicHistory.goBack();
+ sendFlowService.router.goBack();
}
function paste(value) {
@@ -467,11 +468,10 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
confirmData.thirdParty = vm.thirdParty;
}
- sendFlowService.pushState(confirmData);
if (!confirmData.fromWalletId) {
$state.transitionTo('tabs.paymentRequest.confirm', confirmData);
} else {
- $state.transitionTo('tabs.send.review', confirmData);
+ sendFlowService.goNext(confirmData);
$scope.useSendMax = null;
}
}
diff --git a/src/js/controllers/review.controller.js b/src/js/controllers/review.controller.js
index b377bef58..dbf14937f 100644
--- a/src/js/controllers/review.controller.js
+++ b/src/js/controllers/review.controller.js
@@ -80,7 +80,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
function onBeforeEnter(event, data) {
console.log('walletSelector onBeforeEnter sendflow ', sendFlowService.state);
defaults = configService.getDefaults();
- sendFlowData = sendFlowService.getStateClone();
+ sendFlowData = sendFlowService.state.getClone();
originWalletId = sendFlowData.fromWalletId;
satoshis = parseInt(sendFlowData.amount, 10);
toAddress = sendFlowData.toAddress;
@@ -403,7 +403,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
}
function goBack() {
- $ionicHistory.goBack();
+ sendFlowService.router.goBack();
}
function handleDestinationAsAddress(address, originCoin) {
@@ -766,8 +766,12 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
((processName === 'signingTx') && vm.originWallet.m > 1) ||
(processName == 'sendingTx' && !vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal())
) && !isOn) {
+ // Show the popup
vm.sendStatus = 'success';
+ // Clear the send flow service state
+ sendFlowService.state.clear();
+
if ($state.current.name === "tabs.send.review") { // XX SP: Otherwise all open wallets on other devices play this sound if you have been in a send flow before on that device.
soundService.play('misc/payment_sent.mp3');
}
diff --git a/src/js/controllers/shapeshift.js b/src/js/controllers/shapeshift.js
index 43e0790d1..0dac21a11 100644
--- a/src/js/controllers/shapeshift.js
+++ b/src/js/controllers/shapeshift.js
@@ -6,22 +6,6 @@ angular.module('copayApp.controllers').controller('shapeshiftController', functi
$scope.showMyAddress = showMyAddress;
- function generateAddress(wallet, cb) {
- if (!wallet) return;
- walletService.getAddress(wallet, false, function(err, addr) {
- if (err) {
- popupService.showAlert(err);
- }
- return cb(addr);
- });
- }
-
- function showToWallets() {
- $scope.toWallets = $scope.fromWallet.coin === 'btc' ? walletsBch : walletsBtc;
- $scope.onToWalletSelect($scope.toWallets[0]);
- $scope.singleToWallet = $scope.toWallets.length === 1;
- }
-
$scope.$on("$ionicView.beforeEnter", function(event, data) {
walletsBtc = profileService.getWallets({coin: 'btc'});
walletsBch = profileService.getWallets({coin: 'bch'});
@@ -62,18 +46,7 @@ angular.module('copayApp.controllers').controller('shapeshiftController', functi
id: 'shapeshift'
}
};
-
- // Starting new send flow, so ensure everything is reset
- sendFlowService.clear();
- $state.go('tabs.home').then(function() {
- $ionicHistory.clearHistory();
- $state.go('tabs.send').then(function() {
- $timeout(function () {
- sendFlowService.pushState(stateParams);
- $state.transitionTo('tabs.send.origin');
- }, 60);
- });
- });
+ sendFlowService.start(stateParams);
}
function showMyAddress() {
diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.controller.js
similarity index 99%
rename from src/js/controllers/tab-home.js
rename to src/js/controllers/tab-home.controller.js
index 318fcece2..229848df8 100644
--- a/src/js/controllers/tab-home.js
+++ b/src/js/controllers/tab-home.controller.js
@@ -122,8 +122,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
};
$scope.startFreshSend = function() {
- sendFlowService.clear();
- $state.go('tabs.send');
+ sendFlowService.start();
}
$scope.openExternalLink = function() {
diff --git a/src/js/controllers/tab-receive.js b/src/js/controllers/tab-receive.js
index 66d1799f8..320afe320 100644
--- a/src/js/controllers/tab-receive.js
+++ b/src/js/controllers/tab-receive.js
@@ -18,10 +18,10 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.displayBalanceAsFiat = true;
$scope.requestSpecificAmount = function() {
- sendFlowService.pushState({
- toWalletId: $scope.wallet.credentials.walletId
+ sendFlowService.start({
+ toWalletId: $scope.wallet.credentials.walletId,
+ isRequestAmount: true
});
- $state.go('tabs.paymentRequest.amount');
};
$scope.setAddress = function(newAddr, copyAddress) {
diff --git a/src/js/controllers/tab-scan.js b/src/js/controllers/tab-scan.controller.js
similarity index 85%
rename from src/js/controllers/tab-scan.js
rename to src/js/controllers/tab-scan.controller.js
index e838a8ea8..14368ee1c 100644
--- a/src/js/controllers/tab-scan.js
+++ b/src/js/controllers/tab-scan.controller.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.controllers').controller('tabScanController', function(bitcoinUriService, gettextCatalog, popupService, $scope, $log, $timeout, scannerService, incomingData, $state, $ionicHistory, $rootScope, $ionicNavBarDelegate) {
+angular.module('copayApp.controllers').controller('tabScanController', function(gettextCatalog, popupService, $scope, $log, $timeout, scannerService, incomingDataService, $state, $ionicHistory, $rootScope, $ionicNavBarDelegate) {
var scannerStates = {
unauthorized: 'unauthorized',
@@ -111,27 +111,18 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
// Sometimes (testing in Chrome, when reading QR Code) data is an object
// that has a string data.result.
contents = contents.result || contents;
-
- var parsed = bitcoinUriService.parse(contents);
- var title = '';
- var msg = '';
- if (parsed.isValid) {
- if (parsed.isTestnet) {
- title = gettextCatalog.getString('Unsupported');
- msg = gettextCatalog.getString('Testnet is not supported.');
- popupService.showAlert(title, msg, function onAlertShown() {
- scannerService.resumePreview();
+ incomingDataService.redir(contents, function onError(err) {
+ if (err) {
+ var title = gettextCatalog.getString('Scan Failed');
+ popupService.showAlert(title, err.message, function onAlertShown() {
+ // Enable another scan since we won't receive incomingDataMenu.menuHidden
+ activate();
});
} else {
- incomingData.redir(contents);
- }
- } else {
- title = gettextCatalog.getString('Scan Failed');
- msg = gettextCatalog.getString('Data not recognised.');
- popupService.showAlert(title, msg, function onAlertShown() {
scannerService.resumePreview();
- });
- }
+
+ }
+ });
}
$rootScope.$on('incomingDataMenu.menuHidden', function() {
diff --git a/src/js/controllers/tab-send.js b/src/js/controllers/tab-send.controller.js
similarity index 83%
rename from src/js/controllers/tab-send.js
rename to src/js/controllers/tab-send.controller.js
index eba744560..03a9562e8 100644
--- a/src/js/controllers/tab-send.js
+++ b/src/js/controllers/tab-send.controller.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.controllers').controller('tabSendController', function(bitcoinUriService, $scope, $rootScope, $log, $timeout, $ionicScrollDelegate, $ionicLoading, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, sendFlowService, bwcError, gettextCatalog, scannerService, configService, bitcoinCashJsService, $ionicPopup, $ionicNavBarDelegate, clipboardService) {
+angular.module('copayApp.controllers').controller('tabSendController', function(bitcoinUriService, $scope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, platformInfo, sendFlowService, gettextCatalog, configService, $ionicPopup, $ionicNavBarDelegate, clipboardService, incomingDataService) {
var clipboardHasAddress = false;
var clipboardHasContent = false;
var originalList;
@@ -29,7 +29,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
$scope.$on("$ionicView.enter", function(event, data) {
- var stateParams = sendFlowService.getStateClone();
+ var stateParams = sendFlowService.state.getClone();
$scope.fromWallet = profileService.getWallet(stateParams.fromWalletId);
clipboardService.readFromClipboard(function(text) {
@@ -62,11 +62,6 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
});
$scope.findContact = function(search) {
-
- if (incomingData.redir(search)) {
- return;
- }
-
if (!search || search.length < 1) {
$scope.list = originalList;
$timeout(function() {
@@ -75,12 +70,16 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
return;
}
- var result = lodash.filter(originalList, function(item) {
- var val = item.name;
- return lodash.startsWith(val.toLowerCase(), search.toLowerCase());
+ var params = sendFlowService.state.getClone();
+ params.data = search;
+ sendFlowService.start(params, function onError() {
+ var result = lodash.filter(originalList, function(item) {
+ var val = item.name;
+ return lodash.startsWith(val.toLowerCase(), search.toLowerCase());
+ });
+
+ $scope.list = result;
});
-
- $scope.list = result;
};
var hasWallets = function() {
@@ -186,27 +185,18 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
$log.debug('Got toAddress:' + toAddress + ' | ' + item.name);
- var stateParams = sendFlowService.getStateClone();
- stateParams.toAddress = toAddress,
+ var stateParams = sendFlowService.state.getClone();
+ stateParams.toAddress = toAddress;
stateParams.coin = item.coin;
- sendFlowService.pushState(stateParams);
-
- if (!stateParams.fromWalletId) { // If we have no toAddress or fromWallet
- $state.transitionTo('tabs.send.origin');
- } else {
- $state.transitionTo('tabs.send.amount');
- }
-
+ sendFlowService.start(stateParams);
});
};
$scope.startWalletToWalletTransfer = function() {
console.log('startWalletToWalletTransfer()');
- var params = sendFlowService.getStateClone();
- sendFlowService.pushState(params);
- $state.transitionTo('tabs.send.wallet-to-wallet', {
- fromWalletId: sendFlowService.fromWalletId
- });
+ var params = sendFlowService.state.getClone();
+ params.isWalletTransfer = true;
+ sendFlowService.start(params);
}
// This could probably be enhanced refactoring the routes abstract states
@@ -240,7 +230,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
});
if (data.direction == "back") {
- sendFlowService.clear();
+ sendFlowService.state.clear();
}
});
diff --git a/src/js/controllers/tabsController.js b/src/js/controllers/tabsController.js
index b3de6c70f..b78274ecb 100644
--- a/src/js/controllers/tabsController.js
+++ b/src/js/controllers/tabsController.js
@@ -1,11 +1,13 @@
'use strict';
-angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, platformInfo, incomingData, lodash, popupService, gettextCatalog, scannerService, sendFlowService) {
+angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, platformInfo, incomingDataService, lodash, popupService, gettextCatalog, scannerService, sendFlowService) {
$scope.onScan = function(data) {
- if (!incomingData.redir(data)) {
- popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid data'));
- }
+ incomingDataService.redir(data, function onError(err) {
+ if (err) {
+ popupService.showAlert(gettextCatalog.getString('Error'), err.message);
+ }
+ });
};
$scope.setScanFn = function(scanFn) {
@@ -16,8 +18,7 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
};
$scope.startFreshSend = function() {
- sendFlowService.clear();
- $state.go('tabs.send');
+ sendFlowService.start();
};
$scope.importInit = function() {
@@ -28,7 +29,6 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
};
$scope.chooseScanner = function() {
- sendFlowService.clear();
var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
if (!isWindowsPhoneApp) {
@@ -38,10 +38,14 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
scannerService.useOldScanner(function(err, contents) {
if (err) {
- popupService.showAlert(gettextCatalog.getString('Error'), err);
- return;
+ popupService.showAlert(gettextCatalog.getString('Error'), err.message);
+ } else {
+ incomingDataService.redir(contents, function onError(err) {
+ if (err) {
+ popupService.showAlert(gettextCatalog.getString('Error'), err.message);
+ }
+ });
}
- incomingData.redir(contents);
});
};
diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/wallet-details.controller.js
similarity index 94%
rename from src/js/controllers/walletDetails.js
rename to src/js/controllers/wallet-details.controller.js
index ec787a5f4..9d306039f 100644
--- a/src/js/controllers/walletDetails.js
+++ b/src/js/controllers/wallet-details.controller.js
@@ -26,27 +26,6 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
};
var setPendingTxps = function(txps) {
-
- /* Uncomment to test multiple outputs */
-
- // var txp = {
- // message: 'test multi-output',
- // fee: 1000,
- // createdOn: new Date() / 1000,
- // outputs: [],
- // wallet: $scope.wallet
- // };
- //
- // function addOutput(n) {
- // txp.outputs.push({
- // amount: 600,
- // toAddress: '2N8bhEwbKtMvR2jqMRcTCQqzHP6zXGToXcK',
- // message: 'output #' + (Number(n) + 1)
- // });
- // };
- // lodash.times(15, addOutput);
- // txps.push(txp);
-
if (!txps) {
$scope.txps = [];
return;
@@ -378,8 +357,6 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
- sendFlowService.clear();
-
configService.whenAvailable(function (config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
@@ -477,16 +454,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
}
$scope.goToSend = function() {
- sendFlowService.startSend({
+ sendFlowService.start({
fromWalletId: $scope.wallet.id
});
- // Go home first so that the Home tab works properly
- $state.go('tabs.home').then(function () {
- $ionicHistory.clearHistory();
- $state.go('tabs.send');
- });
-
};
$scope.goToReceive = function() {
$state.go('tabs.home', {
diff --git a/src/js/controllers/walletSelectorController.js b/src/js/controllers/wallet-selector.controller.js
similarity index 81%
rename from src/js/controllers/walletSelectorController.js
rename to src/js/controllers/wallet-selector.controller.js
index 6a5b96cbf..06e6179da 100644
--- a/src/js/controllers/walletSelectorController.js
+++ b/src/js/controllers/wallet-selector.controller.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.controllers').controller('walletSelectorController', function($scope, $rootScope, $state, $log, $ionicHistory, sendFlowService, configService, gettextCatalog, profileService, txFormatService) {
+angular.module('copayApp.controllers').controller('walletSelectorController', function($scope, $state, sendFlowService, configService, gettextCatalog, profileService, txFormatService) {
var fromWalletId = '';
var priceDisplayAsFiat = false;
@@ -12,31 +12,22 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
function onBeforeEnter(event, data) {
if (data.direction == "back") {
- sendFlowService.popState();
+ sendFlowService.state.pop();
}
- console.log('walletSelector onBeforeEnter after back sendflow', sendFlowService.state);
- $scope.params = sendFlowService.getStateClone();
+ $scope.params = sendFlowService.state.getClone();
+
+ console.log('walletSelector onBeforeEnter after back sendflow', $scope.params);
var config = configService.getSync().wallet.settings;
priceDisplayAsFiat = config.priceDisplay === 'fiat';
unitDecimals = config.unitDecimals;
unitsFromSatoshis = 1 / config.unitToSatoshi;
- switch($state.current.name) {
- case 'tabs.send.wallet-to-wallet':
- $scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
- break;
- case 'tabs.send.destination':
- if ($scope.params.fromWalletId && !$scope.params.thirdParty) {
- $scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
- }
- break;
- default:
- if (!$scope.params.thirdParty) {
- $scope.sendFlowTitle = gettextCatalog.getString('Send');
- }
- // nop
+ if ($scope.params.isWalletTransfer) {
+ $scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
+ } else if (!$scope.params.thirdParty) {
+ $scope.sendFlowTitle = gettextCatalog.getString('Send');
}
$scope.coin = false; // Wallets to show (for destination screen or contacts)
@@ -105,16 +96,6 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
}
}
- function getNextStep(params) {
- if (!params.toWalletId && !params.toAddress) { // If we have no toAddress or fromWallet
- return 'tabs.send.destination';
- } else if (!params.amount) { // If we have no amount
- return 'tabs.send.amount';
- } else { // If we do have them
- return 'tabs.send.review';
- }
- }
-
function handleThirdPartyIfShapeshift() {
console.log($scope.thirdParty, $scope.coin);
if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the
@@ -192,20 +173,17 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
$scope.useWallet = function(wallet) {
- var params = sendFlowService.getStateClone();
+ var params = sendFlowService.state.getClone();
if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from
params.fromWalletId = wallet.id;
} else { // we're on the destination screen, set wallet to send to
params.toWalletId = wallet.id;
}
- sendFlowService.pushState(params);
- var nextStep = getNextStep(params);
- console.log('walletSelector nextStep', nextStep);
- $state.transitionTo(nextStep, $scope.params);
+ sendFlowService.goNext(params);
};
$scope.goBack = function() {
- $ionicHistory.goBack();
+ sendFlowService.router.goBack();
}
});
\ No newline at end of file
diff --git a/src/js/directives/incomingDataMenu.js b/src/js/directives/incomingDataMenu.js
index 21478102b..78856e62f 100644
--- a/src/js/directives/incomingDataMenu.js
+++ b/src/js/directives/incomingDataMenu.js
@@ -1,23 +1,28 @@
'use strict';
angular.module('copayApp.directives')
- .directive('incomingDataMenu', function($timeout, $rootScope, $state, externalLinkService) {
+ .directive('incomingDataMenu', function($timeout, $rootScope, $state, externalLinkService, sendFlowService, bitcoinCashJsService) {
return {
restrict: 'E',
templateUrl: 'views/includes/incomingDataMenu.html',
link: function(scope, element, attrs) {
$rootScope.$on('incomingDataMenu.showMenu', function(event, data) {
$timeout(function() {
- scope.data = data.data;
- scope.type = data.type;
- scope.showMenu = true;
- scope.https = false;
+ scope.data = data;
- if (scope.type === 'url') {
- if (scope.data.indexOf('https://') === 0) {
- scope.https = true;
- }
+ if (scope.data.parsed.privateKey) {
+ scope.type = "privateKey";
+ } else if (scope.data.parsed.url) {
+ scope.type = "url";
+ } else if (scope.data.parsed.publicAddress) {
+ scope.type = "bitcoinAddress";
+ var prefix = scope.data.parsed.isTestnet ? 'bchtest:' : 'bitcoincash:';
+ scope.data.toAddress = (prefix + scope.data.parsed.publicAddress.cashAddr) || scope.data.parsed.publicAddress.legacy || scope.data.parsed.publicAddress.bitpay;
+ } else {
+ scope.type = "text";
}
+
+ scope.showMenu = true;
});
});
scope.hide = function() {
@@ -28,18 +33,9 @@ angular.module('copayApp.directives')
externalLinkService.open(url);
};
scope.sendPaymentToAddress = function(bitcoinAddress) {
- var noPrefixInAddress = 0;
- if (bitcoinAddress.toLowerCase().indexOf('bitcoin') < 0) {
- noPrefixInAddress = 1;
- }
scope.showMenu = false;
- $state.go('tabs.send').then(function() {
- $timeout(function() {
- $state.transitionTo('tabs.send.amount', {
- toAddress: bitcoinAddress,
- noPrefix: noPrefixInAddress
- });
- }, 50);
+ sendFlowService.start({
+ data: bitcoinAddress
});
};
scope.addToAddressBook = function(bitcoinAddress) {
diff --git a/src/js/directives/shapeshiftCoinTrader.js b/src/js/directives/shapeshiftCoinTrader.js
index 60cc66bdf..793f380fb 100644
--- a/src/js/directives/shapeshiftCoinTrader.js
+++ b/src/js/directives/shapeshiftCoinTrader.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function($interval, shapeshiftApiService, profileService, incomingData, ongoingProcess) {
+angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function($interval, shapeshiftApiService, profileService, incomingDataService, ongoingProcess) {
return {
restrict: 'E',
transclude: true,
@@ -111,7 +111,8 @@ angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function
orderId: $scope.depositInfo.orderId
};
- if (incomingData.redir(sendAddress, 'shapeshift', shapeshiftData)) {
+ // How to handle this
+ if (incomingDataService.redir(sendAddress, 'shapeshift', shapeshiftData)) {
ongoingProcess.set('connectingShapeshift', false);
return;
}
diff --git a/src/js/services/incoming-data.service.js b/src/js/services/incoming-data.service.js
new file mode 100644
index 000000000..eece6d17c
--- /dev/null
+++ b/src/js/services/incoming-data.service.js
@@ -0,0 +1,79 @@
+'use strict';
+
+/**
+ * incomingDataService is an intermediate to redirect either to the sendFlow
+ * or to import/join a wallet.
+ */
+angular.module('copayApp.services').factory('incomingDataService', function(bitcoinUriService, $log, $state, $rootScope, scannerService, sendFlowService, gettextCatalog) {
+
+ var root = {};
+
+ root.showMenu = function(data) {
+ $rootScope.$broadcast('incomingDataMenu.showMenu', data);
+ };
+
+ root.redir = function(data, cbError) {
+ var parsed = bitcoinUriService.parse(data);
+
+ console.log(parsed);
+ $log.debug(parsed);
+
+
+ if (parsed.isValid) {
+ if (parsed.isTestnet) {
+ if (cbError) {
+ var errorMessage = gettextCatalog.getString('Testnet is not supported.');
+ cbError(new Error(errorMessage));
+ }
+ } else {
+ scannerService.pausePreview();
+
+ /**
+ * Strategy for the action
+ */
+ if (parsed.copayInvitation) {
+ $state.go('tabs.home').then(function() {
+ $state.transitionTo('tabs.add.join', {
+ url: data
+ });
+ });
+ } else if (parsed.import) {
+ $state.go('tabs.home').then(function() {
+ $state.transitionTo('tabs.add.import', {
+ code: data
+ });
+ });
+ } else if (
+ !parsed.isValid
+ || parsed.privateKey
+ || (sendFlowService.state.isEmpty() && !parsed.url && !parsed.amount)
+ ) {
+ root.showMenu({
+ original: data,
+ parsed: parsed
+ });
+ } else {
+ var state = sendFlowService.state.getClone();
+ state.data = data;
+
+ sendFlowService.start(state, function onError(err) {
+ /**
+ * OnError, open the menu (link not validated)
+ */
+ root.showMenu({
+ original: data,
+ parsed: parsed
+ });
+ });
+ }
+ }
+ } else {
+ if (cbError) {
+ var errorMessage = gettextCatalog.getString('Data not recognised.');
+ cbError(new Error(errorMessage));
+ }
+ }
+ };
+
+ return root;
+});
diff --git a/src/js/services/incomingData.js b/src/js/services/incomingData.js
deleted file mode 100644
index daba07426..000000000
--- a/src/js/services/incomingData.js
+++ /dev/null
@@ -1,490 +0,0 @@
-'use strict';
-
-angular.module('copayApp.services').factory('incomingData', function(externalLinkService, bitcoinUriService, $log, $state, $timeout, $ionicHistory, bitcore, bitcoreCash, $rootScope, payproService, scannerService, sendFlowService, appConfigService, popupService, gettextCatalog, bitcoinCashJsService) {
-
- var root = {};
-
- root.showMenu = function(data) {
- $rootScope.$broadcast('incomingDataMenu.showMenu', data);
- };
-
- root.redir = function(data, serviceId, serviceData) {
- var originalAddress = null;
- var noPrefixInAddress = 0;
- var allParsed = bitcoinUriService.parse(data);
-
- if (allParsed.isValid && allParsed.isTestnet) {
- popupService.showAlert(
- gettextCatalog.getString('Unsupported'),
- gettextCatalog.getString('Testnet is not supported.')
- );
- return false;
- }
-
- if (data.toLowerCase().indexOf('bitcoin') < 0) {
- noPrefixInAddress = 1;
- }
-
- if (typeof(data) == 'string' && !(/^bitcoin(cash)?:\?r=[\w+]/).exec(data) && (data.toLowerCase().indexOf('bitcoincash:') >= 0 || data[0] == 'q' || data[0] == 'p' || data[0] == 'C' || data[0] == 'H')) {
- try {
- noPrefixInAddress = 0;
-
- if (data[0] == 'p' || data[0] == 'q') {
- data = 'bitcoincash:' + data;
- }
- var paramString = '';
- if (data.indexOf('?') >= 0) {
- paramString = data.substring(data.indexOf('?'));
- data = data.substring(0, data.indexOf('?'));
- }
-
- if (data.indexOf('BITCOINCASH:') >= 0) {
- data = data.toLowerCase();
- }
- originalAddress = data.replace('bitcoincash:', '');
- var legacyAddress = bitcoinCashJsService.readAddress(data).legacy;
- data = 'bitcoincash:' + legacyAddress + paramString;
- } catch (ex) {}
- }
-
- $log.debug('Processing incoming data: ' + data);
-
- function sanitizeUri(data) {
- // Fixes when a region uses comma to separate decimals
- var regex = /[\?\&]amount=(\d+([\,\.]\d+)?)/i;
- var match = regex.exec(data);
- if (!match || match.length === 0) {
- return data;
- }
- var value = match[0].replace(',', '.');
- var newUri = data.replace(regex, value);
-
- // mobile devices, uris like copay://glidera
- newUri.replace('://', ':');
-
- return newUri;
- }
-
- function getParameterByName(name, url) {
- if (!url) return;
- name = name.replace(/[\[\]]/g, "\\$&");
- var regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)"),
- results = regex.exec(url);
- if (!results) return null;
- if (!results[2]) return '';
- return decodeURIComponent(results[2].replace(/\+/g, " "));
- }
-
- function checkPrivateKey(privateKey) {
- try {
- new bitcore.PrivateKey(privateKey, 'livenet');
- } catch (err) {
- return false;
- }
- return true;
- }
-
- function goSend(addr, amount, message, coin, serviceId, serviceData) {
- $state.go('tabs.send', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.send' ? false : true
- });
- // Timeout is required to enable the "Back" button
- $timeout(function() {
- var params = sendFlowService.getStateClone();
-
- if (amount) {
- params.amount = amount;
- }
-
- if (addr) {
- params.toAddress = addr;
- params.displayAddress = originalAddress ? originalAddress : addr;
- }
-
- if (coin) {
- params.coin = coin;
- }
-
- if (noPrefixInAddress) {
- params.noPrefixInAddress = noPrefixInAddress;
- }
-
- if (serviceId) {
- params.thirdParty = [];
- params.thirdParty.id = serviceId;
- params.thirdParty.data = serviceData;
- sendFlowService.pushState(params);
- $state.transitionTo('tabs.send.amount');
- } else {
- sendFlowService.pushState(params);
- $state.transitionTo('tabs.send.origin');
- }
- }, 100);
- }
- // data extensions for Payment Protocol with non-backwards-compatible request
- if (allParsed.isValid && allParsed.coin && allParsed.url && !allParsed.isTestnet) {
- var coin = allParsed.coin;
- data = allParsed.url;
- if (allParsed.coin == 'bch') {
- payproService.getPayProDetailsViaHttp(data, function onGetPayProDetailsViaHttp(err, details) {
- if (err) {
- var message = err.toString();
- if (typeof err.data === 'string') {
- // i.e. 'This invoice is no longer accepting payments'
- message = gettextCatalog.getString(err.data);
- }
- popupService.showAlert(gettextCatalog.getString('Error'), message)
- } else {
- handlePayPro(details, allParsed.coin);
- }
- });
- } else {
- payproService.getPayProDetails(data, allParsed.coin, function onGetPayProDetails(err, details) {
- if (err) {
- popupService.showAlert(gettextCatalog.getString('Error'), err);
- } else {
- handlePayPro(details, allParsed.coin);
- }
- });
- }
- return true;
- }
-
- data = sanitizeUri(data);
-
- var addr = '';
- // Bitcoin URL
- if (bitcore.URI.isValid(data)) {
- var coin = 'btc';
- var parsed = new bitcore.URI(data);
-
- var addr = parsed.address ? parsed.address.toString() : '';
- var message = parsed.message;
-
- var amount = parsed.amount ? parsed.amount : '';
-
- if (parsed.r) {
- payproService.getPayProDetails(parsed.r, coin, function(err, details) {
- if (err) {
- if (addr && amount) goSend(addr, amount, message, coin, serviceId, serviceData);
- else popupService.showAlert(gettextCatalog.getString('Error'), err);
- } else handlePayPro(details, coin);
- });
- } else {
- goSend(addr, amount, message, coin, serviceId, serviceData);
- }
- return true;
- // Cash URI
- } else if (allParsed.isValid && allParsed.coin === 'bch' && allParsed.publicAddress && !allParsed.isTestnet) {
- var prefix = allParsed.isTestnet ? 'bchtest:' : 'bitcoincash:';
- var addrIn = allParsed.publicAddress.legacy || allParsed.publicAddress.bitpay || prefix + allParsed.publicAddress.cashAddr;
- originalAddress = allParsed.publicAddress.cashAddr || allParsed.publicAddress.legacy || allParsed.publicAddress.bitpay;
-
- var addresses = bitcoinCashJsService.readAddress(addrIn);
- if (!addresses) {
- return false;
- }
- addr = addresses.legacy;
- var message = allParsed.message;
-
- var amount = allParsed.amount ? allParsed.amount : '';
-
- // paypro not yet supported on cash
- if (allParsed.url) {
- payproService.getPayProDetails(allParsed.url, allParsed.coin, function(err, details) {
- if (err) {
- if (addr && amount)
- goSend(addr, amount, message, allParsed.coin, serviceId, serviceData);
- else
- popupService.showAlert(gettextCatalog.getString('Error'), err);
- }
- handlePayPro(details, allParsed.coin);
- });
- } else {
- goSend(addr, amount, message, allParsed.coin, serviceId, serviceData);
- }
- return true;
-
- // Cash URI with bitcoin (btc) address version number?
- } else if (bitcore.URI.isValid(data.replace(/^bitcoincash:/,'bitcoin:'))) {
- $log.debug('Handling bitcoincash URI with legacy address');
- var coin = 'bch';
- var parsed = new bitcore.URI(data.replace(/^bitcoincash:/,'bitcoin:'));
-
- var oldAddr = parsed.address ? parsed.address.toString() : '';
- if (!oldAddr) return false;
-
- var addr = '';
-
- var a = bitcore.Address(oldAddr).toObject();
- addr = bitcoreCash.Address.fromObject(a).toString();
-
- // Translate address
- $log.debug('address transalated to:' + addr);
- popupService.showConfirm(
- gettextCatalog.getString('Bitcoin cash Payment'),
- gettextCatalog.getString('Payment address was translated to new Bitcoin Cash address format: ' + addr),
- gettextCatalog.getString('OK'),
- gettextCatalog.getString('Cancel'),
- function(ret) {
- if (!ret) return false;
-
- var message = parsed.message;
- var amount = parsed.amount ? parsed.amount : '';
-
- // paypro not yet supported on cash
- if (parsed.r) {
- payproService.getPayProDetails(parsed.r, coin, function(err, details) {
- if (err) {
- if (addr && amount)
- goSend(addr, amount, message, coin, serviceId, serviceData);
- else
- popupService.showAlert(gettextCatalog.getString('Error'), err);
- }
- handlePayPro(details, coin);
- });
- } else {
- goSend(addr, amount, message, coin, serviceId, serviceData);
- }
- }
- );
- return true;
- // Plain URL
- } else if (allParsed.bareUrl) {
-
- if ($state.includes('tabs.scan')) {
- root.showMenu({
- data: allParsed.bareUrl,
- type: 'url'
- });
- } else {
- externalLinkService.open(
- allParsed.bareUrl,
- true,
- gettextCatalog.getString('Open in web browser'),
- allParsed.bareUrl
- );
- }
- return true;
-
- // Plain Address
- } else if (bitcore.Address.isValid(data, 'livenet') || bitcore.Address.isValid(data, 'testnet')) {
- if ($state.includes('tabs.scan')) {
- root.showMenu({
- data: data,
- type: 'bitcoinAddress'
- });
- } else {
- goToAmountPage(data);
- }
- } else if (bitcoreCash.Address.isValid(data, 'livenet')) {
- if ($state.includes('tabs.scan')) {
- root.showMenu({
- data: data,
- type: 'bitcoinAddress',
- coin: 'bch',
- });
- } else {
- goToAmountPage(data, 'bch');
- }
- } else if (data && data.indexOf(appConfigService.name + '://glidera') === 0) {
- var code = getParameterByName('code', data);
- $ionicHistory.nextViewOptions({
- disableAnimate: true
- });
- $state.go('tabs.home', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.home' ? false : true
- }).then(function() {
- $ionicHistory.nextViewOptions({
- disableAnimate: true
- });
- $state.transitionTo('tabs.buyandsell.glidera', {
- code: code
- });
- });
- return true;
-
- } else if (data && data.indexOf(appConfigService.name + '://coinbase') === 0) {
- var code = getParameterByName('code', data);
- $ionicHistory.nextViewOptions({
- disableAnimate: true
- });
- $state.go('tabs.home', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.home' ? false : true
- }).then(function() {
- $ionicHistory.nextViewOptions({
- disableAnimate: true
- });
- $state.transitionTo('tabs.buyandsell.coinbase', {
- code: code
- });
- });
- return true;
-
- // BitPayCard Authentication
- } else if (data && data.indexOf(appConfigService.name + '://') === 0) {
-
- // Disable BitPay Card
- if (!appConfigService._enabledExtensions.debitcard) return false;
-
- var secret = getParameterByName('secret', data);
- var email = getParameterByName('email', data);
- var otp = getParameterByName('otp', data);
- var reason = getParameterByName('r', data);
-
- $state.go('tabs.home', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.home' ? false : true
- }).then(function() {
- switch (reason) {
- default:
- case '0':
- /* For BitPay card binding */
- $state.transitionTo('tabs.bitpayCardIntro', {
- secret: secret,
- email: email,
- otp: otp
- });
- break;
- }
- });
- return true;
-
- // Join
- } else if (data && data.match(/^copay:[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
- $state.go('tabs.home', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.home' ? false : true
- }).then(function() {
- $state.transitionTo('tabs.add.join', {
- url: data
- });
- });
- return true;
-
- // Old join
- } else if (data && data.match(/^[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
- $state.go('tabs.home', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.home' ? false : true
- }).then(function() {
- $state.transitionTo('tabs.add.join', {
- url: data
- });
- });
- return true;
- } else if (data && (data.substring(0, 2) == '6P' || checkPrivateKey(data))) {
- root.showMenu({
- data: data,
- type: 'privateKey'
- });
- } else if (data && ((data.substring(0, 2) == '1|') || (data.substring(0, 2) == '2|') || (data.substring(0, 2) == '3|'))) {
- $state.go('tabs.home').then(function() {
- $state.transitionTo('tabs.add.import', {
- code: data
- });
- });
- return true;
-
- } else {
- if ($state.includes('tabs.scan')) {
- root.showMenu({
- data: data,
- type: 'text'
- });
- }
- }
- return false;
- };
-
- function goToAmountPage(toAddress, coin) {
- $state.go('tabs.send', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.send' ? false : true
- });
- $timeout(function() {
- var stateParams = {
- toAddress: toAddress,
- displayAddress: toAddress,
- coin: coin,
- noPrefix: 1
- };
- sendFlowService.pushState(stateParams);
- $state.transitionTo('tabs.send.origin');
- }, 100);
- }
-
- function handlePayPro(payProData, coin) {
-
- console.log('payProData', payProData);
-
- var toAddr = payProData.toAddress;
- var amount = payProData.amount;
- var paymentUrl = payProData.url;
- var expires = payProData.expires;
- var time = payProData.time;
-
- if (coin === 'bch') {
- var displayAddr = payProData.outputs[0].address;
- toAddr = bitcoinCashJsService.readAddress('bitcoincash:' + displayAddr).legacy;
- amount = payProData.outputs[0].amount;
- paymentUrl = payProData.paymentUrl;
- expires = Math.floor(new Date(expires).getTime() / 1000)
- time = Math.ceil(new Date(time).getTime() / 1000)
- }
-
- var name = payProData.domain;
-
- if (payProData.memo.indexOf('eGifter') > -1) {
- name = 'eGifter'
- } else if (paymentUrl.indexOf('https://bitpay.com') > -1) {
- name = 'BitPay';
- }
-
- var thirdPartyData = {
- id: 'bip70',
- amount: amount,
- caTrusted: true,
- name: name,
- domain: payProData.domain,
- expires: expires,
- memo: payProData.memo,
- network: 'livenet',
- requiredFeeRate: payProData.requiredFeeRate,
- selfSigned: 0,
- time: time,
- displayAddress: displayAddr,
- toAddress: toAddr,
- url: paymentUrl,
- verified: true
- };
-
- var stateParams = {
- amount: thirdPartyData.amount,
- toAddress: thirdPartyData.toAddress,
- coin: coin,
- thirdParty: thirdPartyData
- };
-
- // fee
- if (thirdPartyData.requiredFeeRate) {
- stateParams.requiredFeeRate = thirdPartyData.requiredFeeRate * 1024;
- }
-
- scannerService.pausePreview();
- $state.go('tabs.send', {}, {
- 'reload': true,
- 'notify': $state.current.name == 'tabs.send' ? false : true
- }).then(function() {
- $timeout(function() {
- sendFlowService.pushState(stateParams); // Need to do more here
- $state.transitionTo('tabs.send.origin');
- });
- });
- }
-
- return root;
-});
diff --git a/src/js/services/openURL.js b/src/js/services/openURL.js
index 0f4d6c666..2cf8d95a5 100644
--- a/src/js/services/openURL.js
+++ b/src/js/services/openURL.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, platformInfo, lodash, profileService, incomingData, appConfigService) {
+angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, platformInfo, lodash, profileService, incomingDataService, appConfigService) {
var root = {};
var handleOpenURL = function(args) {
@@ -23,9 +23,12 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
document.addEventListener('handleopenurl', handleOpenURL, false);
- if (!incomingData.redir(url)) {
- $log.warn('Unknown URL! : ' + url);
- }
+ incomingDataService.redir(url, function onError(err) {
+ if (err) {
+ $log.warn('Unknown URL! : ' + url);
+ popupService.showAlert(gettextCatalog.getString('Error'), err.message);
+ }
+ });
};
var handleResume = function() {
diff --git a/src/js/services/send-flow-router.service.js b/src/js/services/send-flow-router.service.js
new file mode 100644
index 000000000..32aa8420b
--- /dev/null
+++ b/src/js/services/send-flow-router.service.js
@@ -0,0 +1,85 @@
+'use strict';
+
+(function(){
+
+angular
+ .module('bitcoincom.services')
+ .factory('sendFlowRouterService', sendFlowRouterService);
+
+ function sendFlowRouterService(
+ sendFlowStateService
+ , $state, $ionicHistory, $timeout
+ ) {
+
+ var service = {
+ // Functions
+ start: start,
+ goNext: goNext,
+ goBack: goBack,
+ };
+
+ return service;
+
+ /**
+ * Start new send flow
+ */
+ function start() {
+ var state = sendFlowStateService.state;
+
+ if (state.isRequestAmount) {
+ $state.go('tabs.paymentRequest.amount');
+ } else {
+ if ($state.current.name != 'tabs.send') {
+ $state.go('tabs.home').then(function () {
+ $ionicHistory.clearHistory();
+ $state.go('tabs.send').then(function () {
+ $timeout(function () {
+ goNext();
+ }, 60);
+ });
+ });
+ } else {
+ goNext();
+ }
+ }
+ }
+
+ /**
+ * Go to the next page
+ * Routing strategy : https://bitcoindotcom.atlassian.net/wiki/x/BQDWKQ
+ */
+ function goNext() {
+ var state = sendFlowStateService.state;
+
+ var needsDestination = !state.toWalletId && !state.toAddress;
+ var needsOrigin = !state.fromWalletId;
+ var needsAmount = !state.amount && !state.sendMax;
+
+ if (needsDestination) {
+ if (!state.isWalletTransfer && !state.thirdParty) {
+ $state.go('tabs.send');
+ return;
+ } else if (!needsOrigin) {
+ $state.go('tabs.send.destination');
+ return;
+ }
+ }
+
+ if (needsOrigin) {
+ $state.go('tabs.send.origin');
+ } else if (needsAmount) {
+ $state.go('tabs.send.amount');
+ } else {
+ $state.go('tabs.send.review');
+ }
+ }
+
+ /**
+ * Go to the previous page
+ */
+ function goBack() {
+ $ionicHistory.goBack();
+ }
+ };
+
+})();
\ No newline at end of file
diff --git a/src/js/services/sendFlowService.js b/src/js/services/send-flow-state.service.js
similarity index 50%
rename from src/js/services/sendFlowService.js
rename to src/js/services/send-flow-state.service.js
index 62989b3c5..bec2c8a3c 100644
--- a/src/js/services/sendFlowService.js
+++ b/src/js/services/send-flow-state.service.js
@@ -3,14 +3,13 @@
(function(){
angular
- .module('copayApp.services')
- .factory('sendFlowService', sendFlowService);
+ .module('bitcoincom.services')
+ .factory('sendFlowStateService', sendFlowStateService);
- function sendFlowService($log) {
+ function sendFlowStateService($log) {
var service = {
- // A separate state variable so we can ensure it is cleared of everything,
- // even other properties added that this service does not know about. (such as "coin")
+ // Variables
state: {
amount: '',
displayAddress: null,
@@ -18,29 +17,55 @@ angular
sendMax: false,
thirdParty: null,
toAddress: '',
- toWalletId: ''
+ toWalletId: '',
+ coin: '',
+ isRequestAmount: false,
+ isWalletTransfer: false
},
previousStates: [],
// Functions
+ init: init,
clear: clear,
- getStateClone: getStateClone,
+ getClone: getClone,
map: map,
- popState: popState,
- pushState: pushState,
- startSend: startSend
+ pop: pop,
+ push: push,
+ isEmpty: isEmpty
};
return service;
+ /**
+ * Init state & stack
+ * @param {Object} params
+ */
+ function init(params) {
+ $log.debug("send-flow-state init()");
+
+ clear();
+
+ if (params) {
+ push(params);
+ }
+ }
+
+ /**
+ * Clear a state & stack
+ */
function clear() {
- console.log("sendFlow clear()");
+ $log.debug("send-flow-state clear()");
+
clearCurrent();
service.previousStates = [];
}
+ /**
+ * Clear current state only
+ */
function clearCurrent() {
- console.log("sendFlow clearCurrent()");
+ $log.debug("send-flow-state clearCurrent()");
+
service.state = {
amount: '',
displayAddress: null,
@@ -48,14 +73,17 @@ angular
sendMax: false,
thirdParty: null,
toAddress: '',
- toWalletId: ''
+ toWalletId: '',
+ coin: '',
+ isRequestAmount: false,
+ isWalletTransfer: false
}
}
/**
- * Handy for debugging
+ * Get a clone of the current state
*/
- function getStateClone() {
+ function getClone() {
var currentState = {};
Object.keys(service.state).forEach(function forCurrentParam(key) {
if (typeof service.state[key] !== 'function' && key !== 'previousStates') {
@@ -66,22 +94,21 @@ angular
}
/**
- * Clears all previous state
+ * Fill in the current state from the params
+ * @param {Object} params
*/
- function startSend(params) {
- console.log('startSend()');
- clear();
- map(params);
- }
-
function map(params) {
Object.keys(params).forEach(function forNewParam(key) {
service.state[key] = params[key];
});
};
- function popState() {
- console.log('sendFlow pop');
+ /**
+ * Pop state
+ */
+ function pop() {
+ $log.debug('send-flow-state pop');
+
if (service.previousStates.length) {
var params = service.previousStates.pop();
clearCurrent();
@@ -91,13 +118,25 @@ angular
}
};
- function pushState(params) {
- console.log('sendFlow push');
- var currentParams = getStateClone();
+ /**
+ * Push state
+ * @param {Object} params
+ */
+ function push(params) {
+ $log.debug('send-flow-state push');
+
+ var currentParams = getClone();
service.previousStates.push(currentParams);
clearCurrent();
map(params);
};
+
+ /**
+ * Is empty stack
+ */
+ function isEmpty() {
+ return service.previousStates.length == 0;
+ };
};
})();
\ No newline at end of file
diff --git a/src/js/services/send-flow.service.js b/src/js/services/send-flow.service.js
new file mode 100644
index 000000000..1b02c0d34
--- /dev/null
+++ b/src/js/services/send-flow.service.js
@@ -0,0 +1,149 @@
+'use strict';
+
+(function(){
+
+angular
+ .module('bitcoincom.services')
+ .factory('sendFlowService', sendFlowService);
+
+ function sendFlowService(
+ sendFlowStateService, sendFlowRouterService
+ , bitcoinUriService, payproService, bitcoinCashJsService
+ , popupService, gettextCatalog
+ , $state, $log
+ ) {
+
+ var service = {
+ // Variables
+ state: sendFlowStateService,
+ router: sendFlowRouterService,
+
+ // Functions
+ start: start,
+ goNext: goNext,
+ goBack: goBack
+ };
+
+ return service;
+
+ /**
+ * Start a new send flow
+ * @param {Object} params
+ * @param {Function} onError
+ */
+ function start(params, onError) {
+ $log.debug('send-flow start()');
+
+ if (params && params.data) {
+ var res = bitcoinUriService.parse(params.data);
+
+ if (res.isValid) {
+
+ // If BIP70 (url)
+ if (res.url) {
+ var url = res.url;
+ var coin = res.coin || '';
+ payproService.getPayProDetails(url, coin, function onGetPayProDetails(err, payProData) {
+ if (err) {
+ popupService.showAlert(gettextCatalog.getString('Error'), err);
+ } else {
+ var name = payProData.domain;
+
+ // Detect some merchant that we know
+ if (payProData.memo.indexOf('eGifter') > -1) {
+ name = 'eGifter'
+ } else if (paymentUrl.indexOf('https://bitpay.com') > -1) {
+ name = 'BitPay';
+ }
+
+ // Init thirdParty
+ var thirdPartyData = {
+ id: 'bip70',
+ caTrusted: true,
+ name: name,
+ domain: payProData.domain,
+ expires: payProData.expires,
+ memo: payProData.memo,
+ network: 'livenet',
+ requiredFeeRate: payProData.requiredFeeRate,
+ selfSigned: 0,
+ time: payProData.time,
+ url: payProData.url,
+ verified: true
+ };
+
+ // Fill in params
+ params.amount = payProData.amount,
+ params.toAddress = payProData.toAddress,
+ params.coin = coin,
+ params.thirdParty = thirdPartyData
+ }
+
+ // Resolve
+ _next();
+ });
+ } else {
+ if (res.coin) {
+ params.coin = res.coin;
+ }
+
+ if (res.amountInSatoshis) {
+ params.amount = res.amountInSatoshis;
+ }
+
+ if (res.publicAddress) {
+ var prefix = res.isTestnet ? 'bchtest:' : 'bitcoincash:';
+ params.displayAddress = res.publicAddress.cashAddr || res.publicAddress.legacy || res.publicAddress.bitpay;
+ var formatAddress = res.publicAddress.cashAddr ? prefix + params.displayAddress : params.displayAddress;
+ params.toAddress = bitcoinCashJsService.readAddress(formatAddress).legacy;
+ }
+
+ _next();
+ }
+ } else {
+ if (onError) {
+ onError();
+ }
+ }
+ } else {
+ _next();
+ }
+
+
+ // Next used for sync the async task
+ function _next() {
+ sendFlowStateService.init(params);
+
+ // Routing strategy to -> send-flow-router.service
+ sendFlowRouterService.start();
+ }
+ }
+
+ /**
+ * Go to the next step
+ * @param {Object} state
+ */
+ function goNext(state) {
+ $log.debug('send-flow goNext()');
+
+ // Save the current route before leaving
+ state.route = $state.current.name;
+
+ // Save the state and redirect the user
+ sendFlowStateService.push(state);
+ sendFlowRouterService.goNext();
+ }
+
+ /**
+ * Go to the previous step
+ */
+ function goBack() {
+ $log.debug('send-flow goBack()');
+
+ // Remove the state on top and redirect the user
+ sendFlowStateService.pop();
+ sendFlowRouterService.goBack();
+ }
+ };
+
+})();
\ No newline at end of file
diff --git a/src/js/services/shapeshiftService.js b/src/js/services/shapeshiftService.js
index 1ce9672ce..b1d2f6e7d 100644
--- a/src/js/services/shapeshiftService.js
+++ b/src/js/services/shapeshiftService.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.services').factory('shapeshiftService', function ($http, $interval, $log, lodash, moment, ongoingProcess, shapeshiftApiService, storageService, configService, incomingData, platformInfo, servicesService) {
+angular.module('copayApp.services').factory('shapeshiftService', function ($http, $interval, $log, lodash, moment, ongoingProcess, shapeshiftApiService, storageService, configService, incomingDataService, platformInfo, servicesService) {
var root = {};
root.ShiftState = 'Shift';
root.coinIn = '';
@@ -111,7 +111,7 @@ angular.module('copayApp.services').factory('shapeshiftService', function ($http
toAddress: txData.deposit
};
//
- // if (incomingData.redir(sendAddress, 'shapeshift', shapeshiftData)) {
+ // if (incomingDataService.redir(sendAddress, 'shapeshift', shapeshiftData)) {
ongoingProcess.set('connectingShapeshift', false);
// return;
// }
diff --git a/www/views/includes/incomingDataMenu.html b/www/views/includes/incomingDataMenu.html
index 1d66b616a..e60d7e956 100644
--- a/www/views/includes/incomingDataMenu.html
+++ b/www/views/includes/incomingDataMenu.html
@@ -9,21 +9,21 @@