import 'package:camera/camera.dart'; import 'package:flutter/foundation.dart'; import '../../core/utils/file_helper.dart'; abstract class CameraDataSource { Future getCameraController(); Future captureImage(CameraController controller); Future disposeCamera(CameraController controller); Future startImageStream(CameraController controller, Function(CameraImage) onImage); Future stopImageStream(CameraController controller); } class CameraDataSourceImpl implements CameraDataSource { @override Future getCameraController() async { List cameras = []; try { cameras = await availableCameras(); } catch (e) { debugPrint("availableCameras() failed: $e"); } if (cameras.isEmpty) { if (kIsWeb) { debugPrint("No cameras found. Attempting Web Fallback with default configuration."); // Fallback for Web: Create a generic camera description. // This attempts to bypass enumeration issues caused by browser privacy blocks. cameras = [ const CameraDescription( name: 'Default Web Camera', lensDirection: CameraLensDirection.external, // Use external/front as default safe bet sensorOrientation: 0, ), ]; } else { throw Exception('No cameras available. Please ensure camera permission is granted.'); } } // Web-safe image format selection ImageFormatGroup? formatGroup; if (!kIsWeb) { formatGroup = defaultTargetPlatform == TargetPlatform.android ? ImageFormatGroup.yuv420 : ImageFormatGroup.bgra8888; } // Use medium resolution for better Web compatibility // 'low' might be even safer for initial connection final controller = CameraController( cameras.first, kIsWeb ? ResolutionPreset.medium : ResolutionPreset.high, enableAudio: false, imageFormatGroup: formatGroup, ); try { await controller.initialize(); return controller; } catch (e) { debugPrint("Controller initialization failed: $e"); throw Exception("Failed to start camera: $e"); } } @override Future captureImage(CameraController controller) async { final image = await controller.takePicture(); return await FileHelper.saveCapturedImage(image); } @override Future disposeCamera(CameraController controller) async { await controller.dispose(); } @override Future startImageStream(CameraController controller, Function(CameraImage) onImage) async { // Web: check if streaming is supported to avoid assertion error if (kIsWeb) { try { if (!controller.value.isStreamingImages) { await controller.startImageStream(onImage); } } catch (e) { debugPrint("Web Image Stream failed (expected on some browsers): $e"); } return; } // Native logic if (!controller.value.isStreamingImages) { await controller.startImageStream(onImage); } } @override Future stopImageStream(CameraController controller) async { try { if (controller.value.isStreamingImages) { await controller.stopImageStream(); } } catch (e) { // ignore } } }