refactor(scanner): improve barcode scanner initialization and error handling
- Fix scanner listener initialization in class component * Replace Vue ref with direct class property for scanListener * Remove unnecessary .value accesses throughout the code - Enhance error handling and cleanup * Add proper cleanup on scanner errors * Add cleanup in stopScanning method * Improve error message formatting * Add error handling in handleScanResult - Improve state management * Move state updates into try/catch blocks * Add finally block to reset state after scan processing * Better handling of processing states during scanning - Add comprehensive logging * Log each step of scanner initialization * Add detailed error logging * Format object logs to prevent [object Object] output - Code style improvements * Fix indentation throughout the file * Consistent error handling patterns * Better code organization and readability
This commit is contained in:
@@ -137,7 +137,7 @@ import {
|
||||
BarcodeScanner,
|
||||
type ScanResult,
|
||||
} from "@capacitor-mlkit/barcode-scanning";
|
||||
import { ref, type Ref, reactive } from "vue";
|
||||
import { ref, reactive } from "vue";
|
||||
|
||||
// Declare global constants
|
||||
declare const __USE_QR_READER__: boolean;
|
||||
@@ -241,7 +241,7 @@ export default class ContactQRScanShowView extends Vue {
|
||||
private isCapturingPhoto = false;
|
||||
private appStateListener?: { remove: () => Promise<void> };
|
||||
|
||||
private scanListener: Ref<PluginListenerHandle | null> = ref(null);
|
||||
private scanListener: PluginListenerHandle | null = null;
|
||||
private state = reactive<AppState>({
|
||||
isProcessing: false,
|
||||
processingStatus: "",
|
||||
@@ -307,7 +307,17 @@ export default class ContactQRScanShowView extends Vue {
|
||||
this.appStateListener = await App.addListener(
|
||||
"appStateChange",
|
||||
(state: AppStateChangeEvent) => {
|
||||
logger.log("App state changed:", state);
|
||||
const stateInfo = {
|
||||
isActive: state.isActive,
|
||||
timestamp: new Date().toISOString(),
|
||||
cameraActive: this.cameraActive,
|
||||
scannerState: {
|
||||
...this.state.scannerState,
|
||||
// Convert complex objects to strings to avoid [object Object]
|
||||
error: this.state.scannerState.error?.toString() || null,
|
||||
},
|
||||
};
|
||||
logger.log("App state changed:", JSON.stringify(stateInfo, null, 2));
|
||||
if (!state.isActive) {
|
||||
this.cleanupCamera();
|
||||
}
|
||||
@@ -316,15 +326,31 @@ export default class ContactQRScanShowView extends Vue {
|
||||
|
||||
// Add pause listener
|
||||
await App.addListener("pause", () => {
|
||||
logger.log("App paused");
|
||||
const pauseInfo = {
|
||||
timestamp: new Date().toISOString(),
|
||||
cameraActive: this.cameraActive,
|
||||
scannerState: {
|
||||
...this.state.scannerState,
|
||||
error: this.state.scannerState.error?.toString() || null,
|
||||
},
|
||||
isProcessing: this.state.isProcessing,
|
||||
};
|
||||
logger.log("App paused:", JSON.stringify(pauseInfo, null, 2));
|
||||
this.cleanupCamera();
|
||||
});
|
||||
|
||||
// Add resume listener
|
||||
await App.addListener("resume", () => {
|
||||
logger.log("App resumed");
|
||||
// Don't automatically reinitialize camera on resume
|
||||
// Let user explicitly request camera access again
|
||||
const resumeInfo = {
|
||||
timestamp: new Date().toISOString(),
|
||||
cameraActive: this.cameraActive,
|
||||
scannerState: {
|
||||
...this.state.scannerState,
|
||||
error: this.state.scannerState.error?.toString() || null,
|
||||
},
|
||||
isProcessing: this.state.isProcessing,
|
||||
};
|
||||
logger.log("App resumed:", JSON.stringify(resumeInfo, null, 2));
|
||||
});
|
||||
|
||||
logger.log("App lifecycle listeners setup complete");
|
||||
@@ -436,41 +462,59 @@ export default class ContactQRScanShowView extends Vue {
|
||||
try {
|
||||
this.state.isProcessing = true;
|
||||
this.state.processingStatus = "Starting camera...";
|
||||
logger.log("Opening mobile camera - starting initialization");
|
||||
|
||||
// Check current permission status
|
||||
const status = await BarcodeScanner.checkPermissions();
|
||||
logger.log("Camera permission status:", JSON.stringify(status, null, 2));
|
||||
|
||||
if (status.camera !== "granted") {
|
||||
// Request permission if not granted
|
||||
logger.log("Requesting camera permissions...");
|
||||
const permissionStatus = await BarcodeScanner.requestPermissions();
|
||||
if (permissionStatus.camera !== "granted") {
|
||||
throw new Error("Camera permission not granted");
|
||||
}
|
||||
logger.log(
|
||||
"Camera permission granted:",
|
||||
JSON.stringify(permissionStatus, null, 2),
|
||||
);
|
||||
}
|
||||
|
||||
// Remove any existing listener first
|
||||
try {
|
||||
if (this.scanListener) {
|
||||
logger.log("Removing existing barcode listener");
|
||||
await this.scanListener.remove();
|
||||
this.scanListener = null;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error removing existing listener:", error);
|
||||
// Continue with setup even if removal fails
|
||||
}
|
||||
|
||||
// Set up the listener before starting the scan
|
||||
try {
|
||||
const listener = await BarcodeScanner.addListener(
|
||||
logger.log("Setting up new barcode listener");
|
||||
this.scanListener = await BarcodeScanner.addListener(
|
||||
"barcodesScanned",
|
||||
async (result: ScanResult) => {
|
||||
logger.log(
|
||||
"Barcode scan result received:",
|
||||
JSON.stringify(result, null, 2),
|
||||
);
|
||||
if (result.barcodes && result.barcodes.length > 0) {
|
||||
this.state.processingDetails = `Processing QR code: ${result.barcodes[0].rawValue}`;
|
||||
await this.handleScanResult(result.barcodes[0].rawValue);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Only set the listener if we successfully got one
|
||||
if (listener) {
|
||||
this.scanListener.value = listener;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error setting up barcode listener:", error);
|
||||
throw new Error("Failed to initialize barcode scanner");
|
||||
}
|
||||
logger.log("Barcode listener setup complete");
|
||||
|
||||
// Start the scanner
|
||||
logger.log("Starting barcode scanner");
|
||||
await BarcodeScanner.startScan();
|
||||
logger.log("Barcode scanner started successfully");
|
||||
|
||||
this.state.isProcessing = false;
|
||||
this.state.processingStatus = "";
|
||||
} catch (error) {
|
||||
@@ -481,19 +525,37 @@ export default class ContactQRScanShowView extends Vue {
|
||||
this.showError(
|
||||
error instanceof Error ? error.message : "Failed to open camera",
|
||||
);
|
||||
|
||||
// Cleanup on error
|
||||
try {
|
||||
if (this.scanListener) {
|
||||
await this.scanListener.remove();
|
||||
this.scanListener = null;
|
||||
}
|
||||
} catch (cleanupError) {
|
||||
logger.error("Error during cleanup:", cleanupError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async handleScanResult(rawValue: string) {
|
||||
try {
|
||||
this.state.isProcessing = true;
|
||||
this.state.processingStatus = "Processing QR code...";
|
||||
this.state.processingDetails = `Scanned value: ${rawValue}`;
|
||||
try {
|
||||
|
||||
// Stop scanning before processing
|
||||
await this.stopScanning();
|
||||
|
||||
// Process the scan result
|
||||
await this.onScanDetect({ rawValue });
|
||||
} catch (error) {
|
||||
logger.error("Error handling scan result:", error);
|
||||
this.showError("Failed to process scan result");
|
||||
} finally {
|
||||
this.state.isProcessing = false;
|
||||
this.state.processingStatus = "";
|
||||
this.state.processingDetails = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -880,6 +942,13 @@ export default class ContactQRScanShowView extends Vue {
|
||||
|
||||
async stopScanning() {
|
||||
try {
|
||||
// Remove the listener first
|
||||
if (this.scanListener) {
|
||||
await this.scanListener.remove();
|
||||
this.scanListener = null;
|
||||
}
|
||||
|
||||
// Stop the scanner
|
||||
await BarcodeScanner.stopScan();
|
||||
this.state.scannerState.processingStatus = "Scan stopped";
|
||||
this.state.scannerState.isProcessing = false;
|
||||
@@ -889,6 +958,7 @@ export default class ContactQRScanShowView extends Vue {
|
||||
error instanceof Error ? error.message : String(error);
|
||||
this.state.scannerState.error = `Error stopping scan: ${errorMessage}`;
|
||||
this.state.scannerState.isProcessing = false;
|
||||
logger.error("Error stopping scanner:", error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user