mirror of https://github.com/BTCPrivate/copay.git
This commit is contained in:
parent
246f1927dc
commit
d5d3f9ee28
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabScanController', function($scope, $timeout, $ionicModal, $log, $ionicPopup, configService, gettextCatalog, platformInfo, bitcore, lodash, $state, walletService) {
|
||||
angular.module('copayApp.controllers').controller('tabScanController', function($scope, $timeout, $ionicModal, $log, $ionicPopup, configService, gettextCatalog, platformInfo, bitcore, lodash, $state, incomingData) {
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
|
@ -22,7 +22,7 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
|
|||
|
||||
var _dataScanned = function(data) {
|
||||
$log.debug('Scanned:' + data);
|
||||
if (!walletService.redirFromUri(data)) {
|
||||
if (!incomingData.redir(data)) {
|
||||
$log.warn('Fail to process scanned data');
|
||||
_showAlert('Bad bitcoin address', 'Could not recognize the bitcoin address', function(res) {
|
||||
$scope.init();
|
||||
|
@ -84,7 +84,6 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
// QR code Scanner
|
||||
var video;
|
||||
var canvas;
|
|
@ -63,7 +63,7 @@
|
|||
ng-show="addressbookForm.address.$invalid && addressbookEntry.address"></i>
|
||||
</div>
|
||||
<div class="qr-scan-icon">
|
||||
<qr-scanner on-scan="onQrCodeScanned(data, addressbookForm)"></qr-scanner>
|
||||
<qr-scanner on-scan="onQrCodeScanned(data)"></qr-scanner>
|
||||
<input type="text"
|
||||
id="address"
|
||||
name="address"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<ion-modal-view>
|
||||
<ion-modal-view ng-controller="scannerController" ng-init="init()">
|
||||
<ion-header-bar align-title="center" class="bar-stable">
|
||||
<button ng-click="cancel()" class="button button-clear button-positive" translate>
|
||||
Close
|
||||
</button>
|
||||
<h1 class="title ellipsis" translate>QR-Scanner</h1>
|
||||
</ion-header-bar>
|
||||
<ion-content ng-controller="tabScanController" ng-init="init()">
|
||||
<ion-content >
|
||||
<canvas id="qr-canvas" width="200" height="150"></canvas>
|
||||
<video id="qrcode-scanner-video" width="300" height="225"></video>
|
||||
</ion-content>
|
||||
|
|
|
@ -3,7 +3,7 @@ Create tabs with an icon and label, using the tabs-positive style.
|
|||
Each tab's child <ion-nav-view> directive will have its own
|
||||
navigation history that also transitions its views in and out.
|
||||
-->
|
||||
<ion-tabs class="tabs-icon-top tabs-color-active-positive">
|
||||
<ion-tabs class="tabs-icon-top tabs-color-active-positive" ng-controller="tabsController">
|
||||
|
||||
<ion-tab title="Home" icon-off="ion-ios-pulse" icon-on="ion-ios-pulse-strong" href="#/tabs/home">
|
||||
<ion-nav-view name="tab-home"></ion-nav-view>
|
||||
|
@ -14,11 +14,13 @@ navigation history that also transitions its views in and out.
|
|||
</ion-tab>
|
||||
|
||||
|
||||
<ion-tab title="Scan" icon-off="ion-ios-camera-outline" icon-on="ion-ios-camera" href="#/tabs/scan">
|
||||
<ion-nav-view name="tab-scan"></ion-nav-view>
|
||||
</ion-tab>
|
||||
<!-- this actually NEVER gets rendered -->
|
||||
<qr-scanner class="qr-icon size-24" style="display:none" set-fn="setScanFn(theScanFn)" on-scan="onScan(data)"></qr-scanner>
|
||||
|
||||
|
||||
<ion-tab title="Scan" icon-off="ion-ios-camera" ng-click="scan()" >
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab title="Send" icon-off="ion-ios-chatboxes-outline" icon-on="ion-ios-chatboxes" href="#/tabs/send">
|
||||
<ion-nav-view name="tab-send"></ion-nav-view>
|
||||
</ion-tab>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('joinController',
|
||||
function($scope, $rootScope, $timeout, $state, profileService, configService, storageService, applicationService, gettext, lodash, ledger, trezor, platformInfo, derivationPathHelper, ongoingProcess, walletService, $log) {
|
||||
function($scope, $rootScope, $timeout, $state, profileService, configService, storageService, applicationService, gettext, lodash, ledger, trezor, platformInfo, derivationPathHelper, ongoingProcess, walletService, $log, $stateParams) {
|
||||
|
||||
var isChromeApp = platformInfo.isChromeApp;
|
||||
var isDevel = platformInfo.isDevel;
|
||||
|
@ -12,12 +12,22 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
$scope.derivationPath = derivationPathHelper.default;
|
||||
$scope.account = 1;
|
||||
|
||||
|
||||
this.onQrCodeScanned = function(data) {
|
||||
console.log('[join.js.16:data:]',data); //TODO
|
||||
$scope.secret = data;
|
||||
$scope.joinForm.secret.$setViewValue(data);
|
||||
$scope.joinForm.secret.$render();
|
||||
if ($scope.joinForm) {
|
||||
$scope.joinForm.secret.$setViewValue(data);
|
||||
$scope.joinForm.secret.$render();
|
||||
}
|
||||
};
|
||||
|
||||
if ($stateParams.url) {
|
||||
var data = $stateParams.url;
|
||||
data = data.replace('copay:', '');
|
||||
this.onQrCodeScanned(data);
|
||||
}
|
||||
|
||||
var updateSeedSourceSelect = function() {
|
||||
self.seedOptions = [{
|
||||
id: 'new',
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('scannerController', function($scope, $timeout) {
|
||||
|
||||
// QR code Scanner
|
||||
var video;
|
||||
var canvas;
|
||||
var $video;
|
||||
var context;
|
||||
var localMediaStream;
|
||||
var prevResult;
|
||||
var scanTimer;
|
||||
|
||||
var _scan = function(evt) {
|
||||
if (localMediaStream) {
|
||||
context.drawImage(video, 0, 0, 300, 225);
|
||||
try {
|
||||
qrcode.decode();
|
||||
} catch (e) {
|
||||
//qrcodeError(e);
|
||||
}
|
||||
}
|
||||
scanTimer = $timeout(_scan, 800);
|
||||
};
|
||||
|
||||
var _scanStop = function() {
|
||||
$timeout.cancel(scanTimer);
|
||||
if (localMediaStream && localMediaStream.active) {
|
||||
var localMediaStreamTrack = localMediaStream.getTracks();
|
||||
for (var i = 0; i < localMediaStreamTrack.length; i++) {
|
||||
localMediaStreamTrack[i].stop();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
localMediaStream.stop();
|
||||
} catch (e) {
|
||||
// Older Chromium not support the STOP function
|
||||
};
|
||||
}
|
||||
localMediaStream = null;
|
||||
video.src = '';
|
||||
};
|
||||
|
||||
qrcode.callback = function(data) {
|
||||
if (prevResult != data) {
|
||||
prevResult = data;
|
||||
return;
|
||||
}
|
||||
_scanStop();
|
||||
$scope.cancel();
|
||||
$scope.onScan({
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
var _successCallback = function(stream) {
|
||||
video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
|
||||
localMediaStream = stream;
|
||||
video.play();
|
||||
$timeout(_scan, 1000);
|
||||
};
|
||||
|
||||
var _videoError = function(err) {
|
||||
$scope.cancel();
|
||||
};
|
||||
|
||||
var setScanner = function() {
|
||||
navigator.getUserMedia = navigator.getUserMedia ||
|
||||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
|
||||
navigator.msGetUserMedia;
|
||||
window.URL = window.URL || window.webkitURL ||
|
||||
window.mozURL || window.msURL;
|
||||
};
|
||||
|
||||
$scope.init = function() {
|
||||
setScanner();
|
||||
$timeout(function() {
|
||||
if ($scope.beforeScan) {
|
||||
$scope.beforeScan();
|
||||
}
|
||||
canvas = document.getElementById('qr-canvas');
|
||||
context = canvas.getContext('2d');
|
||||
|
||||
video = document.getElementById('qrcode-scanner-video');
|
||||
$video = angular.element(video);
|
||||
canvas.width = 300;
|
||||
canvas.height = 225;
|
||||
context.clearRect(0, 0, 300, 225);
|
||||
|
||||
navigator.getUserMedia({
|
||||
video: true
|
||||
}, _successCallback, _videoError);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
_scanStop();
|
||||
$scope.scannerModal.hide();
|
||||
$scope.scannerModal.remove();
|
||||
};
|
||||
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabSendController', function($scope, $ionicModal, $log, $timeout, addressbookService, profileService, lodash, $state, walletService, bitcore ) {
|
||||
angular.module('copayApp.controllers').controller('tabSendController', function($scope, $ionicModal, $log, $timeout, addressbookService, profileService, lodash, $state, walletService, incomingData ) {
|
||||
|
||||
var originalList;
|
||||
|
||||
|
@ -55,16 +55,8 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
$scope.findContact = function(search, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
if (search.indexOf('bitcoin:') === 0) {
|
||||
if (!walletService.redirFromUri(search)) {
|
||||
$log.error(err);
|
||||
}
|
||||
} else if (/^https?:\/\//.test(search)) {
|
||||
return $state.go('send.confirm', {paypro: search})
|
||||
} else if (bitcore.Address.isValid(search, 'livenet')) {
|
||||
return $state.go('send.amount', {toAddress: search})
|
||||
} else if (bitcore.Address.isValid(search, 'testnet')) {
|
||||
return $state.go('send.amount', {toAddress: search})
|
||||
if (incomingData.redir(search)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!search || search.length < 2) {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabsController', function($log, $scope, $ionicModal, incomingData) {
|
||||
|
||||
$scope.onScan = function(data) {
|
||||
console.log('[tabsController.js.6:data:]',data); //TODO
|
||||
if (!incomingData.redir(data)) {
|
||||
$ionicPopup.alert({
|
||||
title: 'Invalid data',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.setScanFn = function(scanFn) {
|
||||
$scope.scan = function() {
|
||||
$log.debug('Scanning...');
|
||||
scanFn();
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,16 +1,77 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.directives')
|
||||
.directive('qrScanner', function() {
|
||||
.directive('qrScanner', function($rootScope, $timeout, $ionicModal, gettextCatalog, platformInfo) {
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
var isIOS = platformInfo.isIOS;
|
||||
|
||||
var controller = function($scope) {
|
||||
|
||||
var onSuccess = function(result) {
|
||||
$timeout(function() {
|
||||
window.plugins.spinnerDialog.hide();
|
||||
}, 100);
|
||||
if (isWP && result.cancelled) return;
|
||||
|
||||
$timeout(function() {
|
||||
var data = isIOS ? result : result.text;
|
||||
$scope.onScan({
|
||||
data: data
|
||||
});
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
var onError = function(error) {
|
||||
$timeout(function() {
|
||||
window.plugins.spinnerDialog.hide();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.cordovaOpenScanner = function() {
|
||||
window.plugins.spinnerDialog.show(null, gettextCatalog.getString('Preparing camera...'), true);
|
||||
$timeout(function() {
|
||||
if (isIOS) {
|
||||
cloudSky.zBar.scan({}, onSuccess, onError);
|
||||
} else {
|
||||
cordova.plugins.barcodeScanner.scan(onSuccess, onError);
|
||||
}
|
||||
if ($scope.beforeScan) {
|
||||
$scope.beforeScan();
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.modalOpenScanner = function() {
|
||||
$ionicModal.fromTemplateUrl('views/modals/scanner.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.scannerModal = modal;
|
||||
$scope.scannerModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openScanner = function() {
|
||||
if (isCordova) {
|
||||
$scope.cordovaOpenScanner();
|
||||
} else {
|
||||
$scope.modalOpenScanner();
|
||||
}
|
||||
};
|
||||
$scope.setFn({theScanFn: $scope.openScanner});
|
||||
};
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
onScan: "&",
|
||||
setFn: "&",
|
||||
beforeScan: "&"
|
||||
},
|
||||
controller: 'tabScanController',
|
||||
controller: controller,
|
||||
replace: true,
|
||||
template: '<a on-tap="openScanner()"><i class="icon ion-qr-scanner"></i></a>'
|
||||
template: '<a ng-click="openScanner()"><i class="icon ion-qr-scanner"></i></a>'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -313,14 +313,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.scan', {
|
||||
url: '/scan',
|
||||
views: {
|
||||
'tab-scan': {
|
||||
templateUrl: 'views/tab-scan.html',
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.send', {
|
||||
url: '/send',
|
||||
views: {
|
||||
|
@ -393,7 +385,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
.state('add.join', {
|
||||
url: '/join',
|
||||
url: '/join/:url',
|
||||
views: {
|
||||
'add': {
|
||||
templateUrl: 'views/join.html'
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('incomingData', function($log, $ionicModal, $state, bitcore) {
|
||||
|
||||
var root = {};
|
||||
|
||||
root.redir = function(data) {
|
||||
$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;
|
||||
};
|
||||
|
||||
// data extensions for Payment Protocol with non-backwards-compatible request
|
||||
if ((/^bitcoin:\?r=[\w+]/).exec(data)) {
|
||||
data = decodeURIComponent(data.replace('bitcoin:?r=', ''));
|
||||
$state.go('send.confirm', {paypro: data})
|
||||
}
|
||||
|
||||
|
||||
data = sanitizeUri(data);
|
||||
|
||||
// BIP21
|
||||
if (bitcore.URI.isValid(data)) {
|
||||
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) {
|
||||
$state.go('send.confirm', {paypro: parsed.r});
|
||||
} else {
|
||||
if (amount) {
|
||||
$state.go('send.confirm', {toAmount: amount, toAddress: addr, description:message})
|
||||
} else {
|
||||
$state.go('send.amount', {toAddress: addr})
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// Plain URL
|
||||
} else if (/^https?:\/\//.test(data)) {
|
||||
return $state.go('send.confirm', {paypro: data})
|
||||
|
||||
// Plain Address
|
||||
} else if (bitcore.Address.isValid(data, 'livenet')) {
|
||||
return $state.go('send.amount', {toAddress: data})
|
||||
} else if (bitcore.Address.isValid(data, 'testnet')) {
|
||||
return $state.go('send.amount', {toAddress: data})
|
||||
|
||||
|
||||
// copay: protocol
|
||||
} else if (data.indexOf('copay:glidera')==0) {
|
||||
return $state.go('send.uriglidera', {url: data})
|
||||
} else if (data.indexOf('copay:coinbase')==0) {
|
||||
return $state.go('send.uricoinbase', {url: data})
|
||||
|
||||
// Join
|
||||
} else if (data.match(/^copay:[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
|
||||
return $state.go('add.join', {url: data})
|
||||
|
||||
// Old join
|
||||
} else if (data.match(/^[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
|
||||
return $state.go('add.join', {url: data})
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
|
@ -1,37 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, go, platformInfo, lodash, profileService) {
|
||||
angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, go, platformInfo, lodash, profileService, incomingData) {
|
||||
var root = {};
|
||||
|
||||
root.registeredUriHandlers = [{
|
||||
name: 'Bitcoin BIP21 URL',
|
||||
startsWith: 'bitcoin:',
|
||||
transitionTo: 'uripayment',
|
||||
}, {
|
||||
name: 'Glidera Authentication Callback',
|
||||
startsWith: 'copay:glidera',
|
||||
transitionTo: 'uriglidera',
|
||||
}, {
|
||||
name: 'Coinbase Authentication Callback',
|
||||
startsWith: 'copay:coinbase',
|
||||
transitionTo: 'uricoinbase',
|
||||
}];
|
||||
|
||||
|
||||
var handleOpenURL = function(args) {
|
||||
$log.info('Handling Open URL: ' + JSON.stringify(args));
|
||||
|
||||
if (!profileService.isBound) {
|
||||
$log.warn('Profile not bound yet. Waiting');
|
||||
|
||||
return $rootScope.$on('Local/ProfileBound', function() {
|
||||
// Wait ux to settle
|
||||
setTimeout(function() {
|
||||
$log.warn('Profile ready, retrying...');
|
||||
handleOpenURL(args);
|
||||
}, 2000);
|
||||
});
|
||||
};
|
||||
profileService.whenAvailable(function() {
|
||||
// Wait ux to settle
|
||||
setTimeout(function() {
|
||||
handleOpenURL(args);
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
// Stop it from caching the first view as one to return when the app opens
|
||||
$ionicHistory.nextViewOptions({
|
||||
|
@ -55,19 +35,7 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
|
|||
|
||||
document.addEventListener('handleopenurl', handleOpenURL, false);
|
||||
|
||||
var x = lodash.find(root.registeredUriHandlers, function(x) {
|
||||
return url.indexOf(x.startsWith) == 0 ||
|
||||
url.indexOf('web+' + x.startsWith) == 0 || // web protocols
|
||||
url.indexOf(x.startsWith.replace(':', '://')) == 0 // from mobile devices
|
||||
;
|
||||
});
|
||||
|
||||
if (x) {
|
||||
$log.debug('openURL GOT ' + x.name + ' URL');
|
||||
return $state.transitionTo(x.transitionTo, {
|
||||
url: url
|
||||
});
|
||||
} else {
|
||||
if (!incomingData.redir(url)) {
|
||||
$log.warn('Unknown URL! : ' + url);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1123,50 +1123,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
return finale;
|
||||
};
|
||||
|
||||
// Here?
|
||||
root.redirFromUri = 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;
|
||||
};
|
||||
|
||||
// URI extensions for Payment Protocol with non-backwards-compatible request
|
||||
if ((/^bitcoin:\?r=[\w+]/).exec(uri)) {
|
||||
uri = decodeURIComponent(uri.replace('bitcoin:?r=', ''));
|
||||
$state.go('send.confirm', {paypro: uri})
|
||||
} else {
|
||||
uri = sanitizeUri(uri);
|
||||
|
||||
if (!bitcore.URI.isValid(uri)) {
|
||||
return false;
|
||||
}
|
||||
var parsed = new bitcore.URI(uri);
|
||||
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
|
||||
if (parsed.r) {
|
||||
$state.go('send.confirm', {paypro: parsed.r});
|
||||
} else {
|
||||
if (amount) {
|
||||
$state.go('send.confirm', {toAmount: amount, toAddress: addr, description:message})
|
||||
} else {
|
||||
$state.go('send.amount', {toAddress: addr})
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue