@ -4,7 +4,7 @@ import {
StartScanOptions ,
StartScanOptions ,
LensFacing ,
LensFacing ,
} from "@capacitor-mlkit/barcode-scanning" ;
} from "@capacitor-mlkit/barcode-scanning" ;
import { QRScannerService , ScanListener , QRScannerOptions } from "./types" ;
import { QRScannerService , ScanListener , QRScannerOptions , CameraStateListener , CameraState } from "./types" ;
import { logger } from "@/utils/logger" ;
import { logger } from "@/utils/logger" ;
export class CapacitorQRScanner implements QRScannerService {
export class CapacitorQRScanner implements QRScannerService {
@ -12,6 +12,9 @@ export class CapacitorQRScanner implements QRScannerService {
private isScanning = false ;
private isScanning = false ;
private listenerHandles : Array < ( ) = > Promise < void > > = [ ] ;
private listenerHandles : Array < ( ) = > Promise < void > > = [ ] ;
private cleanupPromise : Promise < void > | null = null ;
private cleanupPromise : Promise < void > | null = null ;
private cameraStateListeners : Set < CameraStateListener > = new Set ( ) ;
private currentState : CameraState = "off" ;
private currentStateMessage? : string ;
async checkPermissions ( ) : Promise < boolean > {
async checkPermissions ( ) : Promise < boolean > {
try {
try {
@ -79,8 +82,11 @@ export class CapacitorQRScanner implements QRScannerService {
}
}
try {
try {
this . updateCameraState ( "initializing" , "Starting camera..." ) ;
// Ensure we have permissions before starting
// Ensure we have permissions before starting
if ( ! ( await this . checkPermissions ( ) ) ) {
if ( ! ( await this . checkPermissions ( ) ) ) {
this . updateCameraState ( "permission_denied" , "Camera permission denied" ) ;
logger . debug ( "Requesting camera permissions" ) ;
logger . debug ( "Requesting camera permissions" ) ;
const granted = await this . requestPermissions ( ) ;
const granted = await this . requestPermissions ( ) ;
if ( ! granted ) {
if ( ! granted ) {
@ -90,11 +96,13 @@ export class CapacitorQRScanner implements QRScannerService {
// Check if scanning is supported
// Check if scanning is supported
if ( ! ( await this . isSupported ( ) ) ) {
if ( ! ( await this . isSupported ( ) ) ) {
this . updateCameraState ( "error" , "QR scanning not supported on this device" ) ;
throw new Error ( "QR scanning not supported on this device" ) ;
throw new Error ( "QR scanning not supported on this device" ) ;
}
}
logger . info ( "Starting MLKit scanner" ) ;
logger . info ( "Starting MLKit scanner" ) ;
this . isScanning = true ;
this . isScanning = true ;
this . updateCameraState ( "active" , "Camera is active" ) ;
const scanOptions : StartScanOptions = {
const scanOptions : StartScanOptions = {
formats : [ BarcodeFormat . QrCode ] ,
formats : [ BarcodeFormat . QrCode ] ,
@ -126,6 +134,7 @@ export class CapacitorQRScanner implements QRScannerService {
stack : wrappedError.stack ,
stack : wrappedError.stack ,
} ) ;
} ) ;
this . isScanning = false ;
this . isScanning = false ;
this . updateCameraState ( "error" , wrappedError . message ) ;
await this . cleanup ( ) ;
await this . cleanup ( ) ;
this . scanListener ? . onError ? . ( wrappedError ) ;
this . scanListener ? . onError ? . ( wrappedError ) ;
throw wrappedError ;
throw wrappedError ;
@ -140,6 +149,7 @@ export class CapacitorQRScanner implements QRScannerService {
try {
try {
logger . debug ( "Stopping QR scanner" ) ;
logger . debug ( "Stopping QR scanner" ) ;
this . updateCameraState ( "off" , "Camera stopped" ) ;
await BarcodeScanner . stopScan ( ) ;
await BarcodeScanner . stopScan ( ) ;
logger . info ( "QR scanner stopped successfully" ) ;
logger . info ( "QR scanner stopped successfully" ) ;
} catch ( error ) {
} catch ( error ) {
@ -149,6 +159,7 @@ export class CapacitorQRScanner implements QRScannerService {
error : wrappedError.message ,
error : wrappedError.message ,
stack : wrappedError.stack ,
stack : wrappedError.stack ,
} ) ;
} ) ;
this . updateCameraState ( "error" , wrappedError . message ) ;
this . scanListener ? . onError ? . ( wrappedError ) ;
this . scanListener ? . onError ? . ( wrappedError ) ;
throw wrappedError ;
throw wrappedError ;
} finally {
} finally {
@ -207,4 +218,23 @@ export class CapacitorQRScanner implements QRScannerService {
// No-op for native scanner
// No-op for native scanner
callback ( null ) ;
callback ( null ) ;
}
}
addCameraStateListener ( listener : CameraStateListener ) : void {
this . cameraStateListeners . add ( listener ) ;
// Immediately notify the new listener of current state
listener . onStateChange ( this . currentState , this . currentStateMessage ) ;
}
removeCameraStateListener ( listener : CameraStateListener ) : void {
this . cameraStateListeners . delete ( listener ) ;
}
private updateCameraState ( state : CameraState , message? : string ) : void {
this . currentState = state ;
this . currentStateMessage = message ;
// Notify all listeners of state change
for ( const listener of this . cameraStateListeners ) {
listener . onStateChange ( state , message ) ;
}
}
}
}