feat(scan): first iteration of full scan view implementation

This commit is contained in:
Jason Dreyzehner 2016-10-11 02:59:21 -04:00
parent 845534c727
commit c0d4fbe5bb
5 changed files with 108 additions and 52 deletions

View File

@ -23,57 +23,71 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
}
function _handleCapabilities(){
if(!$scope.scannerIsAvailable){
$scope.currentState = scannerStates.unavailable;
} else if($scope.scannerIsDenied){
$scope.currentState = scannerStates.denied;
} else if($scope.scannerIsRestricted){
$scope.currentState = scannerStates.denied;
} else if(!$scope.scannerHasPermission){
$scope.currentState = scannerStates.unauthorized;
} else if($scope.scannerHasPermission){
// always update the view
$timeout(function(){
if(!scannerService.isInitialized()){
$scope.currentState = scannerStates.loading;
} else if(!$scope.scannerIsAvailable){
$scope.currentState = scannerStates.unavailable;
} else if($scope.scannerIsDenied){
$scope.currentState = scannerStates.denied;
} else if($scope.scannerIsRestricted){
$scope.currentState = scannerStates.denied;
} else if(!$scope.scannerHasPermission){
$scope.currentState = scannerStates.unauthorized;
}
$log.debug('Scan view state set to: ' + $scope.currentState);
});
}
function _refreshScanView(){
_updateCapabilities();
_handleCapabilities();
if($scope.scannerHasPermission){
activate();
}
}
function _initScanView(){
_updateCapabilities();
_handleCapabilities();
}
$scope.$on("$ionicView.beforeEnter", function() {
$scope.currentState = scannerStates.loading;
});
// This could be much cleaner with a Promise API
// (needs a polyfill for some platforms)
$rootScope.$on('scannerServiceInitialized', function(){
$log.debug('Scanner initialization finished, reinitializing scan view...');
_initScanView();
_refreshScanView();
});
$scope.$on("$ionicView.afterEnter", function() {
if(scannerService.isInitialized()){
_initScanView();
}
// try initializing and refreshing status any time the view is entered
scannerService.gentleInitialize();
});
function activate(){
scannerService.activate(function(){
_updateCapabilities();
_handleCapabilities();
$log.debug('Scanner activated, setting to visible...');
$scope.currentState = scannerStates.visible;
scannerService.scan(function(err, contents){
if(err){
$log.debug('Scan canceled.');
} else if ($state.params.passthroughMode) {
$rootScope.scanResult = contents;
goBack();
} else {
handleSuccessfulScan(contents);
}
});
// pause to update the view
$timeout(function(){
scannerService.scan(function(err, contents){
if(err){
$log.debug('Scan canceled.');
} else if ($state.params.passthroughMode) {
$rootScope.scanResult = contents;
goBack();
} else {
handleSuccessfulScan(contents);
}
});
});
});
}
$scope.activate = activate;
$scope.authorize = function(){
scannerService.initialize(function(){
_refreshScanView();
});
};
$scope.$on("$ionicView.afterLeave", function() {
scannerService.deactivate();
@ -84,6 +98,14 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
incomingData.redir(contents);
}
$scope.openSettings = function(){
scannerService.openSettings();
};
$scope.attemptToReactivate = function(){
scannerService.reinitialize();
};
$scope.toggleLight = function(){
scannerService.toggleLight(function(lightEnabled){
$scope.lightActive = lightEnabled;
@ -98,7 +120,7 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
$timeout(function(){
$scope.cameraToggleActive = false;
$log.debug('Camera toggle control deactivated.');
}, 600);
}, 200);
});
};
@ -106,6 +128,9 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
return $state.params.passthroughMode;
}
function goBack(){
$ionicHistory.nextViewOptions({
disableAnimate: true
});
$ionicHistory.backView().go();
}
$scope.goBack = goBack;

View File

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.directives')
.directive('qrScanner', function($state, $rootScope, $log) {
.directive('qrScanner', function($state, $rootScope, $log, $ionicHistory) {
return {
restrict: 'E',
@ -9,11 +9,14 @@ angular.module('copayApp.directives')
onScan: "&"
},
replace: true,
template: '<a on-tap="openScanner()"><i class="icon ion-qr-scanner"></i></a>',
template: '<a on-tap="openScanner()" nav-transition="none"><i class="icon ion-qr-scanner"></i></a>',
link: function(scope, el, attrs) {
scope.openScanner = function() {
$log.debug('Opening scanner by directive...');
$ionicHistory.nextViewOptions({
disableAnimate: true
});
$state.go('scanner', { passthroughMode: 1 });
};

View File

@ -8,9 +8,8 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
var backCamera = true; // the plugin defaults to the back camera
// Initalize known capabilities
var isAvailable = false;
var hasPermission = isDesktop? true: false;
var isAuthorized = false;
var isAvailable = isDesktop? false: true; // assume camera exists on mobile
var hasPermission = isDesktop? true: false; // assume desktop has permission
var isDenied = false;
var isRestricted = false;
var canEnableLight = false;
@ -59,6 +58,7 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
}
}
var initializeStarted = false;
/**
* If camera access has been granted, pre-initialize the QRScanner. This method
* can be safely called before the scanner is visible to improve perceived
@ -67,27 +67,32 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
* The `status` of QRScanner is returned to the callback.
*/
this.gentleInitialize = function(callback) {
if(initializeStarted){
QRScanner.getStatus(function(status){
_completeInitialization(status, callback);
});
return;
}
initializeStarted = true;
$log.debug('Trying to pre-initialize QRScanner.');
if(!isDesktop){
QRScanner.getStatus(function(status){
_checkCapabilities(status);
if(status.authorized){
$log.debug('Camera permission already granted.');
_initalize(callback);
initialize(callback);
} else {
$log.debug('QRScanner not authorized, waiting to initalize.');
if(typeof callback === "function"){
callback && callback(status);
}
_completeInitialization(status, callback);
}
});
} else {
$log.debug('Camera permission assumed on desktop.');
_initalize(callback);
initialize(callback);
}
};
function _initalize(callback){
function initialize(callback){
$log.debug('Initializing scanner...');
QRScanner.prepare(function(err, status){
if(err){
@ -103,19 +108,25 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
}
});
}
this.initialize = initialize;
// This could be much cleaner with a Promise API
// (needs a polyfill for some platforms)
var initializeCompleted = false;
function _completeInitialization(status, callback){
_checkCapabilities(status);
$rootScope.$emit('scannerServiceInitialized');
initializeCompleted = true;
callback && callback(status);
$rootScope.$emit('scannerServiceInitialized');
if(typeof callback === "function"){
callback(status);
}
}
this.isInitialized = function(){
return initializeCompleted;
}
this.initializeStarted = function(){
return initializeStarted;
}
var nextHide = null;
var nextDestroy = null;
@ -132,7 +143,9 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
$log.debug('Activating scanner...');
QRScanner.show(function(status){
_checkCapabilities(status);
callback(status);
if(typeof callback === "function"){
callback(status);
}
});
if(nextHide !== null){
$timeout.cancel(nextHide);
@ -183,6 +196,12 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
QRScanner.destroy();
}
this.reinitialize = function(callback){
initializeCompleted = false;
QRScanner.destroy();
initialize(callback);
}
/**
* Toggle the device light (if available).
*
@ -228,4 +247,9 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
callback(status);
});
};
this.openSettings = function() {
$log.debug('Attempting to open device settings...');
QRScanner.openSettings();
};
});

View File

@ -4,6 +4,9 @@ $scannerBackgroundColor: #060d2d;
color: #fff;
text-align: center;
background: transparent none;
.bar-header {
opacity: .9;
}
&-has-problems,
&-loading-camera {
background-color: $scannerBackgroundColor;
@ -50,7 +53,8 @@ $scannerBackgroundColor: #060d2d;
}
}
&-loading-camera {
height: 100%;
width: 100%
}
&-camera-ready {
// view background is transparent to show video preview

View File

@ -10,7 +10,7 @@
<ion-content scroll="false">
<div class="ng-hide" id="tab-scan-has-problems" ng-show="currentState === scannerStates.unauthorized || currentState === scannerStates.denied || currentState === scannerStates.unavailable">
<i class="icon zero-state-icon">
<img src="img/tab-icons/ico-receive.svg" />
<img src="img/tab-icons/ico-receive.svg"/>
</i>
<div class="zero-state-heading" translate>Scan QR Codes</div>
<div class="zero-state-description" translate>You can scan bitcoin addresses, payment requests, paper wallets, and more.</div>
@ -18,9 +18,9 @@
<div class="ng-hide zero-state-tldr" ng-show="currentState === scannerStates.unauthorized" translate>Enable the camera to get started.</div>
<div class="ng-hide zero-state-tldr" ng-show="currentState === scannerStates.denied" translate>Enable camera access in your device settings to get started.</div>
<div class="ng-hide zero-state-tldr" ng-show="currentState === scannerStates.unavailable" translate>Please connect a camera to get started.</div>
<button ng-show="currentState === scannerStates.unauthorized" class="ng-hide button button-standard button-primary" ng-click="attemptActivate">Allow Camera Access</button>
<button ng-show="currentState === scannerStates.denied && canOpenSettings" class="ng-hide button button-standard button-primary" ng-click="openSettings">Open Settings</button>
<button ng-show="currentState === scannerStates.unavailable" class="ng-hide button button-standard button-primary">Retry Camera</button>
<button ng-show="currentState === scannerStates.unauthorized" class="ng-hide button button-standard button-primary" ng-click="authorize()">Allow Camera Access</button>
<button ng-show="currentState === scannerStates.denied && canOpenSettings" class="ng-hide button button-standard button-primary" ng-click="openSettings()">Open Settings</button>
<button ng-show="currentState === scannerStates.unavailable" class="ng-hide button button-standard button-primary" ng-click="attemptToReactivate()">Retry Camera</button>
</div>
</div>
<div class="ng-show" id="tab-scan-loading-camera" ng-show="currentState === scannerStates.loading"></div>