cordova-plugin-qrscanner
Version:
Fast, energy-efficient, highly-configurable QR code scanner.
285 lines (236 loc) • 7.03 kB
JavaScript
const preview = require('./preview');
const barcodeReader = new QRReader.Reader();
const VideoCapture = QRReader.VideoCapture;
const Promise = WinJS.Promise;
const errorTypes = {
UNEXPECTED_ERROR: 0,
CAMERA_ACESS_DENIED: 1,
CAMERA_ACCESS_RESTRICTED: 2,
BACK_CAMERA_UNAVAILABLE: 3,
FRONT_CAMERA_UNAVAILABLE: 4,
CAMERA_UNAVAILABLE: 5,
SCAN_CANCELED: 6,
LIGHT_UNAVAILABLE: 7,
OPEN_SETTINGS_UNAVAILABLE: 8
};
const cameraTypes = {
BACK: 0,
FRONT: 1
};
const defaultStatusFlags = {
prepared: false,
authorized: false,
denied: false,
restricted: false,
scanning: false,
previewing: false,
showing: false,
lightEnabled: false,
canOpenSettings: false,
canEnableLight: false,
canChangeCamera: false,
currentCamera: cameraTypes.BACK
};
let statusFlags;
let currentVideoCapture;
function resetStatusFlags() {
statusFlags = {};
for (let property in defaultStatusFlags) {
statusFlags[property] = defaultStatusFlags[property];
}
return statusFlags;
}
function reset() {
document.body.removeEventListener('click', onPreviewClick);
preview.destroy();
if (currentVideoCapture) currentVideoCapture.destroy();
currentVideoCapture = null;
availableCameras = null;
resetStatusFlags();
}
function generateStatusResponse() {
let response = {};
for (let property in statusFlags) {
response[property] = statusFlags[property] ? '1' : '0';
}
return Promise.wrap(response);
}
function init() {
if (!statusFlags.prepared) {
document.body.addEventListener('click', onPreviewClick);
return VideoCapture.getCamerasAsync().then(function (cameras) {
if (cameras.back && cameras.front) {
statusFlags.canChangeCamera = true;
}
if (!cameras.back && !cameras.front) {
return Promise.wrapError(errorTypes.CAMERA_UNAVAILABLE);
}
availableCameras = cameras;
return initCamera().then(function () {
statusFlags.prepared = true;
statusFlags.authorized = true;
});
});
}
return Promise.wrap();
}
function initCamera(cameraType) {
if (cameraType === cameraTypes.BACK && !availableCameras.back) {
return Promise.wrapError(errorTypes.BACK_CAMERA_UNAVAILABLE);
}
if (cameraType === cameraTypes.FRONT && !availableCameras.front) {
return Promise.wrapError(errorTypes.FRONT_CAMERA_UNAVAILABLE);
}
if (!cameraType) {
if (availableCameras.front) {
cameraType = cameraTypes.FRONT;
}
if (availableCameras.back) {
cameraType = cameraTypes.BACK;
}
}
preview.setVideoUrl('');
return VideoCapture.createAsync(cameraType ? availableCameras.front : availableCameras.back).then(function (videoCapture) {
currentVideoCapture = videoCapture;
let videoUrl = URL.createObjectURL(currentVideoCapture.capture);
if (statusFlags.showing) {
preview.pause();
}
preview.setVideoUrl(videoUrl);
if (statusFlags.showing) {
preview.resume();
}
barcodeReader.setCapture(currentVideoCapture.capture);
statusFlags.canEnableLight = currentVideoCapture.canEnableLight;
statusFlags.currentCamera = cameraType;
}, function (error) {
const ACCESS_DENIED = -2147024891;
if (error.number === ACCESS_DENIED) {
statusFlags.denied = true;
return Promise.wrapError(errorTypes.CAMERA_ACESS_DENIED);
}
return Promise.wrapError(errorTypes.UNEXPECTED_ERROR);
});
}
function onPreviewClick(e) {
if (statusFlags.showing && currentVideoCapture) {
currentVideoCapture.focus();
}
}
let qrScanner = {};
qrScanner.getStatus = function () {
return init().then(generateStatusResponse, generateStatusResponse);
}
qrScanner.prepare = function () {
return init().then(generateStatusResponse);
}
qrScanner.useCamera = function (inputStr) {
return init().then(function () {
let cameraType = parseInt(inputStr);
return initCamera(cameraType).then(function () {
return generateStatusResponse();
});
});
}
qrScanner.show = function () {
return init().then(function () {
preview.show();
statusFlags.showing = true;
statusFlags.previewing = preview.isPlaying();
return generateStatusResponse();
});
}
qrScanner.hide = function () {
return init().then(function () {
preview.hide();
statusFlags.showing = false;
statusFlags.previewing = false;
return generateStatusResponse();
});
}
let resolveLastScanPromise, rejectLastScanPromise;
qrScanner.scan = function () {
if (statusFlags.scanning) {
rejectLastScanPromise(errorTypes.SCAN_CANCELED);
let lastScanPromise = new Promise(function (resolve, reject) {
resolveLastScanPromise = resolve;
rejectLastScanPromise = reject;
});
return lastScanPromise;
}
let lastScanPromise = new Promise(function (resolve, reject) {
resolveLastScanPromise = resolve;
rejectLastScanPromise = reject;
});
init().then(function () {
barcodeReader.readCode().then(function (result) {
if (!result) {
return rejectLastScanPromise(errorTypes.SCAN_CANCELED);
}
resolveLastScanPromise(result.text);
statusFlags.scanning = false;
});
}, function (error) {
statusFlags.scanning = false;
return rejectLastScanPromise(error);
});
statusFlags.scanning = true;
return lastScanPromise;
}
qrScanner.cancelScan = function () {
if (!statusFlags.scanning) return generateStatusResponse();
statusFlags.scanning = false;
barcodeReader.stop();
return generateStatusResponse();
}
qrScanner.pausePreview = function () {
preview.pause();
statusFlags.previewing = false;
return generateStatusResponse();
}
qrScanner.resumePreview = function () {
preview.resume();
statusFlags.previewing = statusFlags.showing;
return generateStatusResponse();
}
//on Lumia devices, light functionality may be disabled while plugged in
qrScanner.enableLight = function () {
return init().then(function () {
if (statusFlags.lightEnabled) {
return generateStatusResponse();
}
statusFlags.lightEnabled = currentVideoCapture.enableLight();
if (!statusFlags.lightEnabled) {
return Promise.wrapError(errorTypes.LIGHT_UNAVAILABLE);
}
return generateStatusResponse();
});
}
qrScanner.disableLight = function () {
if (statusFlags.lightEnabled) {
currentVideoCapture.disableLight();
}
return generateStatusResponse();
}
qrScanner.openSettings = function () {
return Promise.wrapError(errorTypes.OPEN_SETTINGS_UNAVAILABLE);
}
qrScanner.destroy = function () {
reset();
return generateStatusResponse();
}
reset();
function wrapPromise(fn) {
return function (successCallback, errorCallback, strInput) {
fn.call(window, strInput).then(successCallback, function (errorCode) {
errorCallback(errorCode.toString() || '0');
});
}
}
for (let property in qrScanner) {
if (typeof qrScanner[property] == "function") {
exports[property] = wrapPromise(qrScanner[property])
}
}
module.exports = exports;
cordova.commandProxy.add("QRScanner", exports);