107 lines
3.3 KiB
Dart
107 lines
3.3 KiB
Dart
import 'package:camera/camera.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import '../../core/utils/file_helper.dart';
|
|
|
|
abstract class CameraDataSource {
|
|
Future<CameraController> getCameraController();
|
|
Future<String> captureImage(CameraController controller);
|
|
Future<void> disposeCamera(CameraController controller);
|
|
Future<void> startImageStream(CameraController controller, Function(CameraImage) onImage);
|
|
Future<void> stopImageStream(CameraController controller);
|
|
}
|
|
|
|
class CameraDataSourceImpl implements CameraDataSource {
|
|
@override
|
|
Future<CameraController> getCameraController() async {
|
|
List<CameraDescription> 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<String> captureImage(CameraController controller) async {
|
|
final image = await controller.takePicture();
|
|
return await FileHelper.saveCapturedImage(image);
|
|
}
|
|
|
|
@override
|
|
Future<void> disposeCamera(CameraController controller) async {
|
|
await controller.dispose();
|
|
}
|
|
|
|
@override
|
|
Future<void> 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<void> stopImageStream(CameraController controller) async {
|
|
try {
|
|
if (controller.value.isStreamingImages) {
|
|
await controller.stopImageStream();
|
|
}
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
}
|
|
} |