refactor(QRScanner): Align with platform service architecture

- Reorganize QR scanner to follow platform service pattern
- Move QR scanner implementations to services/platforms directory
- Update QRScannerFactory to use PlatformServiceFactory pattern
- Consolidate common QR scanner interfaces with platform services
- Add proper error handling and logging across implementations
- Ensure consistent cleanup and lifecycle management
- Add PyWebView implementation placeholder for desktop
- Update Capacitor and Web implementations to match platform patterns
This commit is contained in:
Matthew Raymer
2025-04-17 06:59:43 +00:00
parent b79cccc591
commit ea13250e5d
6 changed files with 599 additions and 159 deletions

View File

@@ -0,0 +1,88 @@
import {
BarcodeScanner,
BarcodeFormat,
LensFacing,
} from "@capacitor-mlkit/barcode-scanning";
import type { PluginListenerHandle } from "@capacitor/core";
import { QRScannerService, ScanListener } from "./types";
export class NativeQRScanner implements QRScannerService {
private scanListener: ScanListener | null = null;
private isScanning = false;
private listenerHandle: PluginListenerHandle | null = null;
async checkPermissions(): Promise<boolean> {
const { camera } = await BarcodeScanner.checkPermissions();
return camera === "granted";
}
async requestPermissions(): Promise<boolean> {
const { camera } = await BarcodeScanner.requestPermissions();
return camera === "granted";
}
async isSupported(): Promise<boolean> {
const { supported } = await BarcodeScanner.isSupported();
return supported;
}
async startScan(): Promise<void> {
if (this.isScanning) {
throw new Error("Scanner is already running");
}
try {
this.isScanning = true;
await BarcodeScanner.startScan({
formats: [BarcodeFormat.QrCode],
lensFacing: LensFacing.Back,
});
this.listenerHandle = await BarcodeScanner.addListener(
"barcodesScanned",
async (result) => {
if (result.barcodes.length > 0 && this.scanListener) {
const barcode = result.barcodes[0];
this.scanListener.onScan(barcode.rawValue);
await this.stopScan();
}
},
);
} catch (error) {
this.isScanning = false;
if (this.scanListener?.onError) {
this.scanListener.onError(new Error(String(error)));
}
throw error;
}
}
async stopScan(): Promise<void> {
if (!this.isScanning) {
return;
}
try {
await BarcodeScanner.stopScan();
this.isScanning = false;
} catch (error) {
if (this.scanListener?.onError) {
this.scanListener.onError(new Error(String(error)));
}
throw error;
}
}
addListener(listener: ScanListener): void {
this.scanListener = listener;
}
async cleanup(): Promise<void> {
await this.stopScan();
if (this.listenerHandle) {
await this.listenerHandle.remove();
this.listenerHandle = null;
}
this.scanListener = null;
}
}