import { inRuntime, bridgeAsync } from "../bridge"; import { isSupportWebScan, startScanForWeb, stopScanForWeb, isSupportImageScan, startScanForImage, unlockScanBeep } from "../web"; import { isSupportWxScan, startScanForWx } from "../wx"; import { startScanner, stopScanner } from "../scanner"; import { getConfig } from "../config"; import { toAny } from "../../utils/toany"; let _scan_status = "ready"; let _scan_status_listener = null; let _scan_listener_list = []; let _scan_resolve = null; let _scan_closing = false; let _scan_next_start_time = 0; const SCAN_RESTART_DELAY = 500; function getScanRestartDelay() { return toAny(getConfig("scanRestartDelay"), SCAN_RESTART_DELAY); } function __checkScanner() { if (_scan_listener_list.length > 0) { startScanner((result) => { __scannerResult(result); }); } else { stopScanner(); } } function __match(result, match) { let reg = null; if (!!match && typeof match === "string") { reg = new RegExp(match); } if (!!reg) { return reg.test(result); } return true; } function __result(result) { let matched = false; for (let i = 0; i < _scan_listener_list.length; i++) { const item = _scan_listener_list[i]; if (item.listener && __match(result, item.match)) { matched = true; item.listener({ result, key: item.key }); break; } } if (matched) { _scan_next_start_time = Date.now() + getScanRestartDelay(); } return matched; } function __hasMatchedListener(result) { for (let i = 0; i < _scan_listener_list.length; i++) { const item = _scan_listener_list[i]; if (item.listener && __match(result, item.match)) { return true; } } return false; } function __scanning() { if (_scan_status !== "scanning") { _scan_status = "scanning"; if (_scan_status_listener) { _scan_status_listener({ status: "scanning" }); } } } function __closed() { if (_scan_status !== "ready") { _scan_status = "ready"; if (_scan_status_listener) { _scan_status_listener({ status: "ready" }); } } } function __finishScan() { const resolve = _scan_resolve; _scan_resolve = null; __closed(); return resolve; } function __stopCurrentScan() { if (inRuntime()) { return bridgeAsync("stopScan").catch(() => { // no thing }); } else if (isSupportWebScan()) { return stopScanForWeb().catch(() => { // no thing }); } return Promise.resolve(); } function __scannerResult(result) { if (!__hasMatchedListener(result)) { return; } if (isScanning()) { const resolve = __finishScan(); _scan_closing = true; __stopCurrentScan().then(() => { setTimeout(() => { _scan_closing = false; }, 0); }); __result(result); resolve && resolve({ result }); return; } __result(result); } function __startBridgeScan() { return bridgeAsync("startScan", { closeable: true }).then(resp => { if (!isScanning()) { return resp; } if (!resp || !resp.result) { return resp; } if (__result(resp.result)) { return resp; } if (isScanning()) { return __startBridgeScan(); } return resp; }).catch(err => { if (!isScanning()) { return err; } if (!err || !err.result) { return err; } if (__result(err.result)) { return err; } if (isScanning()) { return __startBridgeScan(); } return err; }); } function __startWxScan() { return startScanForWx({ needResult: 1, scanType: ["qrCode", "barCode"] }).then(resp => { if (!isScanning()) { return resp; } if (!resp || !resp.result) { return resp; } if (__result(resp.result)) { return resp; } if (isScanning()) { return __startWxScan(); } return resp; }).catch(err => { if (!isScanning()) { return err; } if (!err || !err.result) { return err; } if (__result(err.result)) { return err; } if (isScanning()) { return __startWxScan(); } return err; }); } function __startImageScan() { return startScanForImage().then(resp => { if (!isScanning()) { return resp; } if (!resp || !resp.result) { return resp; } if (__result(resp.result)) { return resp; } if (isScanning()) { return __startImageScan(); } return resp; }).catch(err => { if (!isScanning()) { return err; } if (!err || !err.result) { return err; } if (__result(err.result)) { return err; } if (isScanning()) { return __startImageScan(); } return err; }); } export function isScanning() { return _scan_status === "scanning"; } export function clear() { for (let i = 0; i < _scan_listener_list.length; i++) { const item = _scan_listener_list[i]; item.cancel(); } _scan_listener_list.length = 0; __checkScanner(); } export function onScanListener(listener, key, match, level) { if (!key || typeof key !== 'string') { return; } if (typeof listener !== 'function') { return; } let item = null; for (let i = 0; i < _scan_listener_list.length; i++) { const _i = _scan_listener_list[i]; if (_i.key === key) { item = _i; break; } } if (item) { item.level = level; item.match = match; item.listener = listener; } else { item = { key, match: match || "", level: level || 0, listener: listener, cancel: () => { const index = _scan_listener_list.indexOf(item); if (index !== -1) { const items = _scan_listener_list.splice(index, 1); for (let i = 0; i < items.length; i++) { const item = items[i]; item.listener && item.listener({ cancel: 1 }); } } } }; _scan_listener_list.push(item); } // 根据level排序 _scan_listener_list.sort((a, b) => b.level - a.level); __checkScanner(); return item; } export function offScanListener(listener) { for (let i = 0; i < _scan_listener_list.length; i++) { const _i = _scan_listener_list[i]; if (typeof listener === 'string') { if (_i.key === listener) { _i.cancel(); break; } } else if (_i.listener === listener) { _i.cancel(); break; } } __checkScanner(); } export function setStatusListener(listener) { if (typeof listener !== 'function') { return; } _scan_status_listener = listener; } export function getStatus() { return _scan_status; } export function stopScan() { if (!isScanning()) { return; } __stopCurrentScan().then(() => { __closed(); }); } export function startScan() { if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) { return; } Promise.resolve().then(() => { __scanning(); let scannerPromise = new Promise(resolve => { _scan_resolve = resolve; }); let scanPromise = Promise.resolve(); if (inRuntime()) { console.log("startScanForBridge"); scanPromise = __startBridgeScan(); } else if (isSupportWxScan()) { console.log("startScanForWx"); scanPromise = __startWxScan(); } else if (isSupportWebScan()) { console.log("startScanForWeb"); unlockScanBeep(); scanPromise = startScanForWeb(getConfig("webScanCanvasStyle"), __result); } else if (isSupportImageScan()) { console.log("startScanForImage"); scanPromise = __startImageScan(); } else { console.log("Not support scanner"); } return Promise.race([scanPromise, scannerPromise]); }).finally(() => { _scan_resolve = null; __closed(); }); } export function scanVideo() { if (!isSupportWebScan()) { console.log("Not support video scanner"); return; } if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) { return; } unlockScanBeep(); Promise.resolve().then(() => { __scanning(); return startScanForWeb(getConfig("webScanCanvasStyle"), __result).then(resp => { if (resp && resp.result) { __result(resp.result); } throw resp.error; }).catch(err => { }); }).finally(() => { __closed(); }); } export function scanImage() { if (!isSupportImageScan()) { console.log("Not support image scanner"); return; } Promise.resolve().then(() => { __scanning(); return startScanForImage().then(resp => { if (resp && resp.result) { __result(resp.result); } throw resp.error; }).catch(err => { }); }).finally(() => { __closed(); }); }