enum QrCameraBootstrapStatus { ready, detectorUnsupported, permissionError, cameraError, } class QrCameraBootstrapResult { const QrCameraBootstrapResult(this.status, {this.errorDetail = ''}); final QrCameraBootstrapStatus status; final String errorDetail; bool get isReady => status == QrCameraBootstrapStatus.ready; } typedef QrOpenCameraAndPlay = Future Function(); typedef QrStopCamera = Future Function(); bool isQrPermissionError(Object error) { final raw = error.toString(); return raw.contains('NotAllowedError') || raw.contains('PermissionDeniedError') || raw.contains('SecurityError'); } Future bootstrapQrCamera({ required bool hasBarcodeDetector, required QrOpenCameraAndPlay openCameraAndPlay, required QrStopCamera stopCamera, }) async { try { await openCameraAndPlay(); if (!hasBarcodeDetector) { await stopCamera(); return const QrCameraBootstrapResult( QrCameraBootstrapStatus.detectorUnsupported, errorDetail: 'BarcodeDetector is not supported in this browser.', ); } return const QrCameraBootstrapResult(QrCameraBootstrapStatus.ready); } catch (e) { if (isQrPermissionError(e)) { return QrCameraBootstrapResult( QrCameraBootstrapStatus.permissionError, errorDetail: e.toString(), ); } return QrCameraBootstrapResult( QrCameraBootstrapStatus.cameraError, errorDetail: e.toString(), ); } }