feat(core): update session, security system and QR exchange

- Removed session creation and Lightning payment logic
- Refactored security system:
  * no more restrictions
  * all systems enabled on session creation
- Improved QR code exchange for mobile devices
This commit is contained in:
lockbitchat
2025-09-23 20:01:02 -04:00
parent 804b384271
commit 34094956b7
396 changed files with 126516 additions and 11881 deletions

16
node_modules/html5-qrcode/es2015/ui/scanner/base.d.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
export declare class PublicUiElementIdAndClasses {
static ALL_ELEMENT_CLASS: string;
static CAMERA_PERMISSION_BUTTON_ID: string;
static CAMERA_START_BUTTON_ID: string;
static CAMERA_STOP_BUTTON_ID: string;
static TORCH_BUTTON_ID: string;
static CAMERA_SELECTION_SELECT_ID: string;
static FILE_SELECTION_BUTTON_ID: string;
static ZOOM_SLIDER_ID: string;
static SCAN_TYPE_CHANGE_ANCHOR_ID: string;
static TORCH_BUTTON_CLASS_TORCH_ON: string;
static TORCH_BUTTON_CLASS_TORCH_OFF: string;
}
export declare class BaseUiElementFactory {
static createElement<Type extends HTMLElement>(elementType: string, elementId: string): Type;
}

25
node_modules/html5-qrcode/es2015/ui/scanner/base.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
export class PublicUiElementIdAndClasses {
}
PublicUiElementIdAndClasses.ALL_ELEMENT_CLASS = "html5-qrcode-element";
PublicUiElementIdAndClasses.CAMERA_PERMISSION_BUTTON_ID = "html5-qrcode-button-camera-permission";
PublicUiElementIdAndClasses.CAMERA_START_BUTTON_ID = "html5-qrcode-button-camera-start";
PublicUiElementIdAndClasses.CAMERA_STOP_BUTTON_ID = "html5-qrcode-button-camera-stop";
PublicUiElementIdAndClasses.TORCH_BUTTON_ID = "html5-qrcode-button-torch";
PublicUiElementIdAndClasses.CAMERA_SELECTION_SELECT_ID = "html5-qrcode-select-camera";
PublicUiElementIdAndClasses.FILE_SELECTION_BUTTON_ID = "html5-qrcode-button-file-selection";
PublicUiElementIdAndClasses.ZOOM_SLIDER_ID = "html5-qrcode-input-range-zoom";
PublicUiElementIdAndClasses.SCAN_TYPE_CHANGE_ANCHOR_ID = "html5-qrcode-anchor-scan-type-change";
PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_ON = "html5-qrcode-button-torch-on";
PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_OFF = "html5-qrcode-button-torch-off";
export class BaseUiElementFactory {
static createElement(elementType, elementId) {
let element = (document.createElement(elementType));
element.id = elementId;
element.classList.add(PublicUiElementIdAndClasses.ALL_ELEMENT_CLASS);
if (elementType === "button") {
element.setAttribute("type", "button");
}
return element;
}
}
//# sourceMappingURL=base.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../src/ui/scanner/base.ts"],"names":[],"mappings":"AAcA,MAAM,OAAO,2BAA2B;;AAI7B,6CAAiB,GAAG,sBAAsB,CAAC;AAG3C,uDAA2B,GAAG,uCAAuC,CAAC;AAGtE,kDAAsB,GAAG,kCAAkC,CAAC;AAG5D,iDAAqB,GAAG,iCAAiC,CAAC;AAG1D,2CAAe,GAAG,2BAA2B,CAAC;AAG9C,sDAA0B,GAAG,4BAA4B,CAAC;AAG1D,oDAAwB,GAAG,oCAAoC,CAAC;AAGhE,0CAAc,GAAG,+BAA+B,CAAC;AAMjD,sDAA0B,GAAG,sCAAsC,CAAC;AAOpE,uDAA2B,GAAG,8BAA8B,CAAC;AAG7D,wDAA4B,GAAG,+BAA+B,CAAC;AAQ1E,MAAM,OAAO,oBAAoB;IAMtB,MAAM,CAAC,aAAa,CACvB,WAAmB,EAAE,SAAiB;QAEtC,IAAI,OAAO,GAAe,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC;QACvB,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,2BAA2B,CAAC,iBAAiB,CAAC,CAAC;QACrE,IAAI,WAAW,KAAK,QAAQ,EAAE;YAC1B,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;SAC1C;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;CACJ"}

View File

@@ -0,0 +1,17 @@
import { CameraDevice } from "../../camera/core";
export declare class CameraSelectionUi {
private readonly selectElement;
private readonly options;
private readonly cameras;
private constructor();
private render;
disable(): void;
isDisabled(): boolean;
enable(): void;
getValue(): string;
hasValue(value: string): boolean;
setValue(value: string): void;
hasSingleItem(): boolean;
numCameras(): number;
static create(parentElement: HTMLElement, cameras: Array<CameraDevice>): CameraSelectionUi;
}

View File

@@ -0,0 +1,82 @@
import { BaseUiElementFactory, PublicUiElementIdAndClasses } from "./base";
import { Html5QrcodeScannerStrings } from "../../strings";
export class CameraSelectionUi {
constructor(cameras) {
this.selectElement = BaseUiElementFactory
.createElement("select", PublicUiElementIdAndClasses.CAMERA_SELECTION_SELECT_ID);
this.cameras = cameras;
this.options = [];
}
render(parentElement) {
const cameraSelectionContainer = document.createElement("span");
cameraSelectionContainer.style.marginRight = "10px";
const numCameras = this.cameras.length;
if (numCameras === 0) {
throw new Error("No cameras found");
}
if (numCameras === 1) {
cameraSelectionContainer.style.display = "none";
}
else {
const selectCameraString = Html5QrcodeScannerStrings.selectCamera();
cameraSelectionContainer.innerText
= `${selectCameraString} (${this.cameras.length}) `;
}
let anonymousCameraId = 1;
for (const camera of this.cameras) {
const value = camera.id;
let name = camera.label == null ? value : camera.label;
if (!name || name === "") {
name = [
Html5QrcodeScannerStrings.anonymousCameraPrefix(),
anonymousCameraId++
].join(" ");
}
const option = document.createElement("option");
option.value = value;
option.innerText = name;
this.options.push(option);
this.selectElement.appendChild(option);
}
cameraSelectionContainer.appendChild(this.selectElement);
parentElement.appendChild(cameraSelectionContainer);
}
disable() {
this.selectElement.disabled = true;
}
isDisabled() {
return this.selectElement.disabled === true;
}
enable() {
this.selectElement.disabled = false;
}
getValue() {
return this.selectElement.value;
}
hasValue(value) {
for (const option of this.options) {
if (option.value === value) {
return true;
}
}
return false;
}
setValue(value) {
if (!this.hasValue(value)) {
throw new Error(`${value} is not present in the camera list.`);
}
this.selectElement.value = value;
}
hasSingleItem() {
return this.cameras.length === 1;
}
numCameras() {
return this.cameras.length;
}
static create(parentElement, cameras) {
let cameraSelectUi = new CameraSelectionUi(cameras);
cameraSelectUi.render(parentElement);
return cameraSelectUi;
}
}
//# sourceMappingURL=camera-selection-ui.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"camera-selection-ui.js","sourceRoot":"","sources":["../../../../src/ui/scanner/camera-selection-ui.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,16 @@
export type OnCameraZoomValueChangeCallback = (zoomValue: number) => void;
export declare class CameraZoomUi {
private zoomElementContainer;
private rangeInput;
private rangeText;
private onChangeCallback;
private constructor();
private render;
private onValueChange;
setValues(minValue: number, maxValue: number, defaultValue: number, step: number): void;
show(): void;
hide(): void;
setOnCameraZoomValueChangeCallback(onChangeCallback: OnCameraZoomValueChangeCallback): void;
removeOnCameraZoomValueChangeCallback(): void;
static create(parentElement: HTMLElement, renderOnCreate: boolean): CameraZoomUi;
}

View File

@@ -0,0 +1,68 @@
import { BaseUiElementFactory, PublicUiElementIdAndClasses } from "./base";
import { Html5QrcodeScannerStrings } from "../../strings";
export class CameraZoomUi {
constructor() {
this.onChangeCallback = null;
this.zoomElementContainer = document.createElement("div");
this.rangeInput = BaseUiElementFactory.createElement("input", PublicUiElementIdAndClasses.ZOOM_SLIDER_ID);
this.rangeInput.type = "range";
this.rangeText = document.createElement("span");
this.rangeInput.min = "1";
this.rangeInput.max = "5";
this.rangeInput.value = "1";
this.rangeInput.step = "0.1";
}
render(parentElement, renderOnCreate) {
this.zoomElementContainer.style.display
= renderOnCreate ? "block" : "none";
this.zoomElementContainer.style.padding = "5px 10px";
this.zoomElementContainer.style.textAlign = "center";
parentElement.appendChild(this.zoomElementContainer);
this.rangeInput.style.display = "inline-block";
this.rangeInput.style.width = "50%";
this.rangeInput.style.height = "5px";
this.rangeInput.style.background = "#d3d3d3";
this.rangeInput.style.outline = "none";
this.rangeInput.style.opacity = "0.7";
let zoomString = Html5QrcodeScannerStrings.zoom();
this.rangeText.innerText = `${this.rangeInput.value}x ${zoomString}`;
this.rangeText.style.marginRight = "10px";
let $this = this;
this.rangeInput.addEventListener("input", () => $this.onValueChange());
this.rangeInput.addEventListener("change", () => $this.onValueChange());
this.zoomElementContainer.appendChild(this.rangeInput);
this.zoomElementContainer.appendChild(this.rangeText);
}
onValueChange() {
let zoomString = Html5QrcodeScannerStrings.zoom();
this.rangeText.innerText = `${this.rangeInput.value}x ${zoomString}`;
if (this.onChangeCallback) {
this.onChangeCallback(parseFloat(this.rangeInput.value));
}
}
setValues(minValue, maxValue, defaultValue, step) {
this.rangeInput.min = minValue.toString();
this.rangeInput.max = maxValue.toString();
this.rangeInput.step = step.toString();
this.rangeInput.value = defaultValue.toString();
this.onValueChange();
}
show() {
this.zoomElementContainer.style.display = "block";
}
hide() {
this.zoomElementContainer.style.display = "none";
}
setOnCameraZoomValueChangeCallback(onChangeCallback) {
this.onChangeCallback = onChangeCallback;
}
removeOnCameraZoomValueChangeCallback() {
this.onChangeCallback = null;
}
static create(parentElement, renderOnCreate) {
let cameraZoomUi = new CameraZoomUi();
cameraZoomUi.render(parentElement, renderOnCreate);
return cameraZoomUi;
}
}
//# sourceMappingURL=camera-zoom-ui.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"camera-zoom-ui.js","sourceRoot":"","sources":["../../../../src/ui/scanner/camera-zoom-ui.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,19 @@
export type OnFileSelected = (file: File) => void;
export declare class FileSelectionUi {
private readonly fileBasedScanRegion;
private readonly fileScanInput;
private readonly fileSelectionButton;
private constructor();
hide(): void;
show(): void;
isShowing(): boolean;
resetValue(): void;
private createFileBasedScanRegion;
private fileBasedScanRegionDefaultBorder;
private fileBasedScanRegionActiveBorder;
private createDragAndDropMessage;
private setImageNameToButton;
private setInitialValueToButton;
private getFileScanInputId;
static create(parentElement: HTMLDivElement, showOnRender: boolean, onFileSelected: OnFileSelected): FileSelectionUi;
}

View File

@@ -0,0 +1,165 @@
import { Html5QrcodeScannerStrings } from "../../strings";
import { BaseUiElementFactory, PublicUiElementIdAndClasses } from "./base";
export class FileSelectionUi {
constructor(parentElement, showOnRender, onFileSelected) {
this.fileBasedScanRegion = this.createFileBasedScanRegion();
this.fileBasedScanRegion.style.display
= showOnRender ? "block" : "none";
parentElement.appendChild(this.fileBasedScanRegion);
let fileScanLabel = document.createElement("label");
fileScanLabel.setAttribute("for", this.getFileScanInputId());
fileScanLabel.style.display = "inline-block";
this.fileBasedScanRegion.appendChild(fileScanLabel);
this.fileSelectionButton
= BaseUiElementFactory.createElement("button", PublicUiElementIdAndClasses.FILE_SELECTION_BUTTON_ID);
this.setInitialValueToButton();
this.fileSelectionButton.addEventListener("click", (_) => {
fileScanLabel.click();
});
fileScanLabel.append(this.fileSelectionButton);
this.fileScanInput
= BaseUiElementFactory.createElement("input", this.getFileScanInputId());
this.fileScanInput.type = "file";
this.fileScanInput.accept = "image/*";
this.fileScanInput.style.display = "none";
fileScanLabel.appendChild(this.fileScanInput);
let $this = this;
this.fileScanInput.addEventListener("change", (e) => {
if (e == null || e.target == null) {
return;
}
let target = e.target;
if (target.files && target.files.length === 0) {
return;
}
let fileList = target.files;
const file = fileList[0];
let fileName = file.name;
$this.setImageNameToButton(fileName);
onFileSelected(file);
});
let dragAndDropMessage = this.createDragAndDropMessage();
this.fileBasedScanRegion.appendChild(dragAndDropMessage);
this.fileBasedScanRegion.addEventListener("dragenter", function (event) {
$this.fileBasedScanRegion.style.border
= $this.fileBasedScanRegionActiveBorder();
event.stopPropagation();
event.preventDefault();
});
this.fileBasedScanRegion.addEventListener("dragleave", function (event) {
$this.fileBasedScanRegion.style.border
= $this.fileBasedScanRegionDefaultBorder();
event.stopPropagation();
event.preventDefault();
});
this.fileBasedScanRegion.addEventListener("dragover", function (event) {
$this.fileBasedScanRegion.style.border
= $this.fileBasedScanRegionActiveBorder();
event.stopPropagation();
event.preventDefault();
});
this.fileBasedScanRegion.addEventListener("drop", function (event) {
event.stopPropagation();
event.preventDefault();
$this.fileBasedScanRegion.style.border
= $this.fileBasedScanRegionDefaultBorder();
var dataTransfer = event.dataTransfer;
if (dataTransfer) {
let files = dataTransfer.files;
if (!files || files.length === 0) {
return;
}
let isAnyFileImage = false;
for (let i = 0; i < files.length; ++i) {
let file = files.item(i);
if (!file) {
continue;
}
let imageType = /image.*/;
if (!file.type.match(imageType)) {
continue;
}
isAnyFileImage = true;
let fileName = file.name;
$this.setImageNameToButton(fileName);
onFileSelected(file);
dragAndDropMessage.innerText
= Html5QrcodeScannerStrings.dragAndDropMessage();
break;
}
if (!isAnyFileImage) {
dragAndDropMessage.innerText
= Html5QrcodeScannerStrings
.dragAndDropMessageOnlyImages();
}
}
});
}
hide() {
this.fileBasedScanRegion.style.display = "none";
this.fileScanInput.disabled = true;
}
show() {
this.fileBasedScanRegion.style.display = "block";
this.fileScanInput.disabled = false;
}
isShowing() {
return this.fileBasedScanRegion.style.display === "block";
}
resetValue() {
this.fileScanInput.value = "";
this.setInitialValueToButton();
}
createFileBasedScanRegion() {
let fileBasedScanRegion = document.createElement("div");
fileBasedScanRegion.style.textAlign = "center";
fileBasedScanRegion.style.margin = "auto";
fileBasedScanRegion.style.width = "80%";
fileBasedScanRegion.style.maxWidth = "600px";
fileBasedScanRegion.style.border
= this.fileBasedScanRegionDefaultBorder();
fileBasedScanRegion.style.padding = "10px";
fileBasedScanRegion.style.marginBottom = "10px";
return fileBasedScanRegion;
}
fileBasedScanRegionDefaultBorder() {
return "6px dashed #ebebeb";
}
fileBasedScanRegionActiveBorder() {
return "6px dashed rgb(153 151 151)";
}
createDragAndDropMessage() {
let dragAndDropMessage = document.createElement("div");
dragAndDropMessage.innerText
= Html5QrcodeScannerStrings.dragAndDropMessage();
dragAndDropMessage.style.fontWeight = "400";
return dragAndDropMessage;
}
setImageNameToButton(imageFileName) {
const MAX_CHARS = 20;
if (imageFileName.length > MAX_CHARS) {
let start8Chars = imageFileName.substring(0, 8);
let length = imageFileName.length;
let last8Chars = imageFileName.substring(length - 8, length);
imageFileName = `${start8Chars}....${last8Chars}`;
}
let newText = Html5QrcodeScannerStrings.fileSelectionChooseAnother()
+ " - "
+ imageFileName;
this.fileSelectionButton.innerText = newText;
}
setInitialValueToButton() {
let initialText = Html5QrcodeScannerStrings.fileSelectionChooseImage()
+ " - "
+ Html5QrcodeScannerStrings.fileSelectionNoImageSelected();
this.fileSelectionButton.innerText = initialText;
}
getFileScanInputId() {
return "html5-qrcode-private-filescan-input";
}
static create(parentElement, showOnRender, onFileSelected) {
let button = new FileSelectionUi(parentElement, showOnRender, onFileSelected);
return button;
}
}
//# sourceMappingURL=file-selection-ui.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
import { Html5QrcodeScanType } from "../../core";
export declare class ScanTypeSelector {
private supportedScanTypes;
constructor(supportedScanTypes?: Array<Html5QrcodeScanType> | []);
getDefaultScanType(): Html5QrcodeScanType;
hasMoreThanOneScanType(): boolean;
isCameraScanRequired(): boolean;
static isCameraScanType(scanType: Html5QrcodeScanType): boolean;
static isFileScanType(scanType: Html5QrcodeScanType): boolean;
private validateAndReturnScanTypes;
}

View File

@@ -0,0 +1,44 @@
import { Html5QrcodeScanType, Html5QrcodeConstants } from "../../core";
export class ScanTypeSelector {
constructor(supportedScanTypes) {
this.supportedScanTypes = this.validateAndReturnScanTypes(supportedScanTypes);
}
getDefaultScanType() {
return this.supportedScanTypes[0];
}
hasMoreThanOneScanType() {
return this.supportedScanTypes.length > 1;
}
isCameraScanRequired() {
for (const scanType of this.supportedScanTypes) {
if (ScanTypeSelector.isCameraScanType(scanType)) {
return true;
}
}
return false;
}
static isCameraScanType(scanType) {
return scanType === Html5QrcodeScanType.SCAN_TYPE_CAMERA;
}
static isFileScanType(scanType) {
return scanType === Html5QrcodeScanType.SCAN_TYPE_FILE;
}
validateAndReturnScanTypes(supportedScanTypes) {
if (!supportedScanTypes || supportedScanTypes.length === 0) {
return Html5QrcodeConstants.DEFAULT_SUPPORTED_SCAN_TYPE;
}
let maxExpectedValues = Html5QrcodeConstants.DEFAULT_SUPPORTED_SCAN_TYPE.length;
if (supportedScanTypes.length > maxExpectedValues) {
throw `Max ${maxExpectedValues} values expected for `
+ "supportedScanTypes";
}
for (const scanType of supportedScanTypes) {
if (!Html5QrcodeConstants.DEFAULT_SUPPORTED_SCAN_TYPE
.includes(scanType)) {
throw `Unsupported scan type ${scanType}`;
}
}
return supportedScanTypes;
}
}
//# sourceMappingURL=scan-type-selector.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"scan-type-selector.js","sourceRoot":"","sources":["../../../../src/ui/scanner/scan-type-selector.ts"],"names":[],"mappings":"AAUA,OAAO,EACH,mBAAmB,EACnB,oBAAoB,EACvB,MAAM,YAAY,CAAC;AAGpB,MAAM,OAAO,gBAAgB;IAGzB,YAAY,kBAAoD;QAC5D,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,0BAA0B,CACrD,kBAAkB,CAAC,CAAC;IAC5B,CAAC;IAMM,kBAAkB;QACrB,OAAO,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IAMM,sBAAsB;QACzB,OAAO,IAAI,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9C,CAAC;IAGM,oBAAoB;QACvB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,kBAAkB,EAAE;YAC5C,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE;gBAC7C,OAAO,IAAI,CAAC;aACf;SACJ;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAGM,MAAM,CAAC,gBAAgB,CAAC,QAA6B;QACxD,OAAO,QAAQ,KAAK,mBAAmB,CAAC,gBAAgB,CAAC;IAC7D,CAAC;IAGM,MAAM,CAAC,cAAc,CAAC,QAA6B;QACtD,OAAO,QAAQ,KAAK,mBAAmB,CAAC,cAAc,CAAC;IAC3D,CAAC;IAQO,0BAA0B,CAC9B,kBAA8C;QAG9C,IAAI,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE;YACxD,OAAO,oBAAoB,CAAC,2BAA2B,CAAC;SAC3D;QAGD,IAAI,iBAAiB,GACf,oBAAoB,CAAC,2BAA2B,CAAC,MAAM,CAAC;QAC9D,IAAI,kBAAkB,CAAC,MAAM,GAAG,iBAAiB,EAAE;YAC/C,MAAM,OAAO,iBAAiB,uBAAuB;kBAC/C,oBAAoB,CAAC;SAC9B;QAGD,KAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE;YACvC,IAAI,CAAC,oBAAoB,CAAC,2BAA2B;iBAC5C,QAAQ,CAAC,QAAQ,CAAC,EAAE;gBACzB,MAAM,yBAAyB,QAAQ,EAAE,CAAC;aAC7C;SACJ;QAED,OAAO,kBAAkB,CAAC;IAC9B,CAAC;CAEJ"}

View File

@@ -0,0 +1,28 @@
import { BooleanCameraCapability } from "../../camera/core";
export type OnTorchActionFailureCallback = (failureMessage: string) => void;
interface TorchButtonController {
disable(): void;
enable(): void;
setText(text: string): void;
}
export interface TorchButtonOptions {
display: string;
marginLeft: string;
}
export declare class TorchButton implements TorchButtonController {
private readonly torchButton;
private readonly onTorchActionFailureCallback;
private torchController;
private constructor();
private render;
updateTorchCapability(torchCapability: BooleanCameraCapability): void;
getTorchButton(): HTMLButtonElement;
hide(): void;
show(): void;
disable(): void;
enable(): void;
setText(text: string): void;
reset(): void;
static create(parentElement: HTMLElement, torchCapability: BooleanCameraCapability, torchButtonOptions: TorchButtonOptions, onTorchActionFailureCallback: OnTorchActionFailureCallback): TorchButton;
}
export {};

View File

@@ -0,0 +1,118 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Html5QrcodeScannerStrings } from "../../strings";
import { BaseUiElementFactory, PublicUiElementIdAndClasses } from "./base";
class TorchController {
constructor(torchCapability, buttonController, onTorchActionFailureCallback) {
this.isTorchOn = false;
this.torchCapability = torchCapability;
this.buttonController = buttonController;
this.onTorchActionFailureCallback = onTorchActionFailureCallback;
}
isTorchEnabled() {
return this.isTorchOn;
}
flipState() {
return __awaiter(this, void 0, void 0, function* () {
this.buttonController.disable();
let isTorchOnExpected = !this.isTorchOn;
try {
yield this.torchCapability.apply(isTorchOnExpected);
this.updateUiBasedOnLatestSettings(this.torchCapability.value(), isTorchOnExpected);
}
catch (error) {
this.propagateFailure(isTorchOnExpected, error);
this.buttonController.enable();
}
});
}
updateUiBasedOnLatestSettings(isTorchOn, isTorchOnExpected) {
if (isTorchOn === isTorchOnExpected) {
this.buttonController.setText(isTorchOnExpected
? Html5QrcodeScannerStrings.torchOffButton()
: Html5QrcodeScannerStrings.torchOnButton());
this.isTorchOn = isTorchOnExpected;
}
else {
this.propagateFailure(isTorchOnExpected);
}
this.buttonController.enable();
}
propagateFailure(isTorchOnExpected, error) {
let errorMessage = isTorchOnExpected
? Html5QrcodeScannerStrings.torchOnFailedMessage()
: Html5QrcodeScannerStrings.torchOffFailedMessage();
if (error) {
errorMessage += "; Error = " + error;
}
this.onTorchActionFailureCallback(errorMessage);
}
reset() {
this.isTorchOn = false;
}
}
export class TorchButton {
constructor(torchCapability, onTorchActionFailureCallback) {
this.onTorchActionFailureCallback = onTorchActionFailureCallback;
this.torchButton
= BaseUiElementFactory.createElement("button", PublicUiElementIdAndClasses.TORCH_BUTTON_ID);
this.torchController = new TorchController(torchCapability, this, onTorchActionFailureCallback);
}
render(parentElement, torchButtonOptions) {
this.torchButton.innerText
= Html5QrcodeScannerStrings.torchOnButton();
this.torchButton.style.display = torchButtonOptions.display;
this.torchButton.style.marginLeft = torchButtonOptions.marginLeft;
let $this = this;
this.torchButton.addEventListener("click", (_) => __awaiter(this, void 0, void 0, function* () {
yield $this.torchController.flipState();
if ($this.torchController.isTorchEnabled()) {
$this.torchButton.classList.remove(PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_OFF);
$this.torchButton.classList.add(PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_ON);
}
else {
$this.torchButton.classList.remove(PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_ON);
$this.torchButton.classList.add(PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_OFF);
}
}));
parentElement.appendChild(this.torchButton);
}
updateTorchCapability(torchCapability) {
this.torchController = new TorchController(torchCapability, this, this.onTorchActionFailureCallback);
}
getTorchButton() {
return this.torchButton;
}
hide() {
this.torchButton.style.display = "none";
}
show() {
this.torchButton.style.display = "inline-block";
}
disable() {
this.torchButton.disabled = true;
}
enable() {
this.torchButton.disabled = false;
}
setText(text) {
this.torchButton.innerText = text;
}
reset() {
this.torchButton.innerText = Html5QrcodeScannerStrings.torchOnButton();
this.torchController.reset();
}
static create(parentElement, torchCapability, torchButtonOptions, onTorchActionFailureCallback) {
let button = new TorchButton(torchCapability, onTorchActionFailureCallback);
button.render(parentElement, torchButtonOptions);
return button;
}
}
//# sourceMappingURL=torch-button.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"torch-button.js","sourceRoot":"","sources":["../../../../src/ui/scanner/torch-button.ts"],"names":[],"mappings":"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"}