Merge pull request #799 from maraoz/feature/uri-handler
bitcoin uri handling
This commit is contained in:
commit
ea86f45d09
12 changed files with 171 additions and 17 deletions
17
index.html
17
index.html
|
|
@ -883,6 +883,21 @@ on supported browsers please check <a href="http://www.webrtc.org/">http://www.w
|
|||
|
||||
</script>
|
||||
|
||||
<!-- URI PAYMENT -->
|
||||
<script type="text/ng-template" id="uri_payment.html">
|
||||
<h3 class="text-center">
|
||||
Preparing payment...
|
||||
</h3>
|
||||
<div data-ng-init="" data-ng-controller="UriPaymentController">
|
||||
<p>Protocol: {{protocol}}</p>
|
||||
<p>To: {{address}}</p>
|
||||
<p>Amount: {{amount}}</p>
|
||||
<p>Message:</p>
|
||||
<div class="alert-box secondary radius">{{message}}</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<!-- NOT FOUND -->
|
||||
<script type="text/ng-template" id="404.html">
|
||||
<h2 class="text-center">404</h2>
|
||||
|
|
@ -925,6 +940,7 @@ on supported browsers please check <a href="http://www.webrtc.org/">http://www.w
|
|||
<script src="js/services/notifications.js"></script>
|
||||
<script src="js/services/backupService.js"></script>
|
||||
<script src="js/services/isMobile.js"></script>
|
||||
<script src="js/services/uriHandler.js"></script>
|
||||
|
||||
<script src="js/controllers/header.js"></script>
|
||||
<script src="js/controllers/footer.js"></script>
|
||||
|
|
@ -936,6 +952,7 @@ on supported browsers please check <a href="http://www.webrtc.org/">http://www.w
|
|||
<script src="js/controllers/setup.js"></script>
|
||||
<script src="js/controllers/import.js"></script>
|
||||
<script src="js/controllers/settings.js"></script>
|
||||
<script src="js/controllers/uriPayment.js"></script>
|
||||
|
||||
<script src="js/init.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ angular.module('copayApp.controllers').controller('HeaderController',
|
|||
|
||||
$rootScope.$watch('txAlertCount', function(txAlertCount) {
|
||||
if (txAlertCount && txAlertCount > 0) {
|
||||
notification.info('New Transaction', ($rootScope.txAlertCount == 1) ? 'You have a pending transaction proposal' : 'You have ' + $rootScope.txAlertCount + ' pending transaction proposals', txAlertCount);
|
||||
notification.info('New Transaction', ($rootScope.txAlertCount == 1) ?
|
||||
'You have a pending transaction proposal' :
|
||||
'You have ' + $rootScope.txAlertCount + ' pending transaction proposals', txAlertCount);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
return flag;
|
||||
};
|
||||
|
||||
if ($rootScope.pendingPayment) {
|
||||
var pp = $rootScope.pendingPayment;
|
||||
$scope.address = pp.address;
|
||||
var amount = pp.amount / config.unitToSatoshi * 100000000;
|
||||
$scope.amount = amount;
|
||||
}
|
||||
|
||||
// Detect protocol
|
||||
$scope.isHttp = ($window.location.protocol.indexOf('http') === 0);
|
||||
|
||||
|
|
@ -61,6 +68,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
$scope.loading = false;
|
||||
});
|
||||
}
|
||||
$rootScope.pendingPayment = null;
|
||||
});
|
||||
|
||||
// reset fields
|
||||
|
|
@ -265,7 +273,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
};
|
||||
|
||||
$scope.topAmount = function(form) {
|
||||
$scope.amount = $scope.getAvailableAmount();
|
||||
$scope.amount = $scope.getAvailableAmount();
|
||||
form.amount.$pristine = false;
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ angular.module('copayApp.controllers').controller('SigninController',
|
|||
$scope.selectedWalletId = $scope.wallets.length ? $scope.wallets[0].id : null;
|
||||
$scope.openPassword = '';
|
||||
|
||||
if ($rootScope.pendingPayment) {
|
||||
notification.info('Login Required', 'Please open wallet to complete payment');
|
||||
}
|
||||
|
||||
$scope.open = function(form) {
|
||||
if (form && form.$invalid) {
|
||||
notification.error('Error', 'Please enter the required fields');
|
||||
|
|
|
|||
17
js/controllers/uriPayment.js
Normal file
17
js/controllers/uriPayment.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('UriPaymentController', function($rootScope, $scope, $routeParams, $timeout, $location) {
|
||||
var data = decodeURIComponent($routeParams.data);
|
||||
$rootScope.pendingPayment = copay.Structure.parseBitcoinURI($routeParams.data);
|
||||
|
||||
$scope.protocol = $rootScope.pendingPayment.protocol;
|
||||
$scope.address = $rootScope.pendingPayment.address;
|
||||
$scope.amount = $rootScope.pendingPayment.amount;
|
||||
$scope.message = $rootScope.pendingPayment.message;
|
||||
|
||||
$timeout(function() {
|
||||
$location.path('signin');
|
||||
}, 1000);
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -50,4 +50,23 @@ Structure.MAX_NON_HARDENED = MAX_NON_HARDENED;
|
|||
Structure.SHARED_INDEX = SHARED_INDEX;
|
||||
Structure.ID_INDEX = ID_INDEX;
|
||||
|
||||
Structure.parseBitcoinURI = function(uri) {
|
||||
var ret = {};
|
||||
var data = decodeURIComponent(uri);
|
||||
var splitDots = data.split(':');
|
||||
ret.protocol = splitDots[0];
|
||||
data = splitDots[1];
|
||||
var splitQuestion = data.split('?');
|
||||
ret.address = splitQuestion[0];
|
||||
var search = splitQuestion[1];
|
||||
data = JSON.parse('{"' + search.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
|
||||
function(key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value);
|
||||
});
|
||||
ret.amount = parseFloat(data.amount);
|
||||
ret.message = data.message;
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
module.exports = require('soop')(Structure);
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ angular
|
|||
templateUrl: 'addresses.html',
|
||||
validate: true
|
||||
})
|
||||
.when('/join/:id', {
|
||||
templateUrl: 'join.html',
|
||||
validate: true
|
||||
})
|
||||
.when('/transactions', {
|
||||
templateUrl: 'transactions.html',
|
||||
validate: true
|
||||
|
|
@ -49,6 +45,9 @@ angular
|
|||
.when('/unsupported', {
|
||||
templateUrl: 'unsupported.html'
|
||||
})
|
||||
.when('/uri_payment/:data', {
|
||||
templateUrl: 'uri_payment.html'
|
||||
})
|
||||
.otherwise({
|
||||
templateUrl: '404.html'
|
||||
});
|
||||
|
|
@ -64,7 +63,6 @@ angular
|
|||
})
|
||||
.run(function($rootScope, $location) {
|
||||
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
||||
|
||||
if (!util.supports.data) {
|
||||
$location.path('unsupported');
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
var bitcore = require('bitcore');
|
||||
|
||||
angular.module('copayApp.services')
|
||||
.factory('controllerUtils', function($rootScope, $sce, $location, notification, $timeout, Socket, video) {
|
||||
.factory('controllerUtils', function($rootScope, $sce, $location, notification, $timeout, Socket, video, uriHandler) {
|
||||
var root = {};
|
||||
|
||||
root.getVideoMutedStatus = function(copayer) {
|
||||
|
|
@ -64,6 +64,7 @@ angular.module('copayApp.services')
|
|||
};
|
||||
|
||||
root.setupRootVariables = function() {
|
||||
uriHandler.register();
|
||||
$rootScope.unitName = config.unitName;
|
||||
$rootScope.txAlertCount = 0;
|
||||
$rootScope.insightError = 0;
|
||||
|
|
@ -102,7 +103,11 @@ angular.module('copayApp.services')
|
|||
});
|
||||
w.on('ready', function(myPeerID) {
|
||||
$rootScope.wallet = w;
|
||||
$location.path('addresses');
|
||||
if ($rootScope.pendingPayment) {
|
||||
$location.path('send');
|
||||
} else {
|
||||
$location.path('addresses');
|
||||
}
|
||||
if (!config.disableVideo)
|
||||
video.setOwnPeer(myPeerID, w, handlePeerVideo);
|
||||
});
|
||||
|
|
|
|||
12
js/services/uriHandler.js
Normal file
12
js/services/uriHandler.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var UriHandler = function() {};
|
||||
|
||||
UriHandler.prototype.register = function() {
|
||||
var base = window.location.origin + '/';
|
||||
var url = base + '#/uri_payment/%s';
|
||||
navigator.registerProtocolHandler('bitcoin',
|
||||
url, 'Copay');
|
||||
};
|
||||
|
||||
angular.module('copayApp.services').value('uriHandler', new UriHandler());
|
||||
|
|
@ -39,13 +39,34 @@ describe('Structure model', function() {
|
|||
});
|
||||
|
||||
[
|
||||
['m/45\'/0/0/0', {index: 0, isChange: false}],
|
||||
['m/45\'/0/0/1', {index: 1, isChange: false}],
|
||||
['m/45\'/0/0/2', {index: 2, isChange: false}],
|
||||
['m/45\'/0/1/0', {index: 0, isChange: true}],
|
||||
['m/45\'/0/1/1', {index: 1, isChange: true}],
|
||||
['m/45\'/0/1/2', {index: 2, isChange: true}],
|
||||
['m/45\'/0/0/900', {index: 900, isChange: false}],
|
||||
['m/45\'/0/0/0', {
|
||||
index: 0,
|
||||
isChange: false
|
||||
}],
|
||||
['m/45\'/0/0/1', {
|
||||
index: 1,
|
||||
isChange: false
|
||||
}],
|
||||
['m/45\'/0/0/2', {
|
||||
index: 2,
|
||||
isChange: false
|
||||
}],
|
||||
['m/45\'/0/1/0', {
|
||||
index: 0,
|
||||
isChange: true
|
||||
}],
|
||||
['m/45\'/0/1/1', {
|
||||
index: 1,
|
||||
isChange: true
|
||||
}],
|
||||
['m/45\'/0/1/2', {
|
||||
index: 2,
|
||||
isChange: true
|
||||
}],
|
||||
['m/45\'/0/0/900', {
|
||||
index: 900,
|
||||
isChange: false
|
||||
}],
|
||||
].forEach(function(datum) {
|
||||
var path = datum[0];
|
||||
var result = datum[1];
|
||||
|
|
@ -55,5 +76,13 @@ describe('Structure model', function() {
|
|||
i.isChange.should.equal(result.isChange);
|
||||
});
|
||||
});
|
||||
it('should get the correct result for bitcoin uri', function() {
|
||||
var uri = 'bitcoin:19mP9FKrXqL46Si58pHdhGKow88SUPy1V8%3Famount=0.1&message=a%20bitcoin%20donation';
|
||||
var result = Structure.parseBitcoinURI(uri);
|
||||
result.address.should.equal('19mP9FKrXqL46Si58pHdhGKow88SUPy1V8');
|
||||
result.amount.should.equal(0.1);
|
||||
result.message.should.equal('a bitcoin donation');
|
||||
result.protocol.should.equal('bitcoin');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ describe("Unit: Controllers", function() {
|
|||
'<form name="form">' +
|
||||
'<input type="number" id="amount" name="amount" placeholder="Amount" ng-model="amount" min="0.0001" max="10000000" enough-amount required>' +
|
||||
'</form>'
|
||||
);
|
||||
);
|
||||
scope.model = {
|
||||
amount: null
|
||||
};
|
||||
|
|
@ -368,4 +368,30 @@ describe("Unit: Controllers", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('UriPayment Controller', function() {
|
||||
var what;
|
||||
beforeEach(inject(function($controller, $rootScope) {
|
||||
scope = $rootScope.$new();
|
||||
var routeParams = {
|
||||
data: 'bitcoin:19mP9FKrXqL46Si58pHdhGKow88SUPy1V8%3Famount=0.1&message=a%20bitcoin%20donation'
|
||||
};
|
||||
what = $controller('UriPaymentController', {
|
||||
$scope: scope,
|
||||
$routeParams: routeParams
|
||||
});
|
||||
}));
|
||||
|
||||
it('should exist', function() {
|
||||
should.exist(what);
|
||||
});
|
||||
|
||||
it('should parse url correctly', function() {
|
||||
should.exist(what);
|
||||
scope.protocol.should.equal('bitcoin');
|
||||
scope.address.should.equal('19mP9FKrXqL46Si58pHdhGKow88SUPy1V8');
|
||||
scope.amount.should.equal(0.1);
|
||||
scope.message.should.equal('a bitcoin donation');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -181,3 +181,20 @@ describe("Unit: isMobile Service", function() {
|
|||
isMobile.any().should.equal(true);
|
||||
}));
|
||||
});
|
||||
describe("Unit: video service", function() {
|
||||
beforeEach(angular.mock.module('copayApp.services'));
|
||||
it('should contain a video service', inject(function(video) {
|
||||
should.exist(video);
|
||||
}));
|
||||
});
|
||||
describe("Unit: uriHandler service", function() {
|
||||
beforeEach(angular.mock.module('copayApp.services'));
|
||||
it('should contain a uriHandler service', inject(function(uriHandler) {
|
||||
should.exist(uriHandler);
|
||||
}));
|
||||
it('should register', inject(function(uriHandler) {
|
||||
(function() {
|
||||
uriHandler.register();
|
||||
}).should.not.throw();
|
||||
}));
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue