import 'dart:io'; import 'package:camera/camera.dart'; import 'package:farm_tpf/main.dart'; import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:path_provider/path_provider.dart'; class CameraHelper extends StatefulWidget { @override _CameraHelperState createState() => _CameraHelperState(); } /// Returns a suitable camera icon for [direction]. IconData getCameraLensIcon(CameraLensDirection direction) { switch (direction) { case CameraLensDirection.back: return Icons.camera_rear; case CameraLensDirection.front: return Icons.camera_front; case CameraLensDirection.external: return Icons.camera; } throw ArgumentError('Unknown lens direction'); } void logError(String code, String message) => print('Error: $code\nError Message: $message'); class _CameraHelperState extends State with WidgetsBindingObserver { CameraController? controller; String? imagePath; String? videoPath; VoidCallback? videoPlayerListener; bool enableAudio = true; int indexCamera = 0; @override void initState() { super.initState(); controller = CameraController(cameras[indexCamera], ResolutionPreset.medium); controller?.initialize().then((_) { if (!mounted) { return; } setState(() {}); }); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { // App state changed before we got the chance to initialize. if (controller == null || !controller!.value.isInitialized) { return; } if (state == AppLifecycleState.inactive) { controller?.dispose(); } else if (state == AppLifecycleState.resumed) { if (controller != null) { onNewCameraSelected(controller!.description); } } } final GlobalKey _scaffoldKey = GlobalKey(); @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, body: SafeArea( top: false, bottom: false, child: Column( children: [ Expanded( child: Container( child: Padding( padding: const EdgeInsets.all(1.0), child: Center( child: _cameraPreviewWidget(), ), ), decoration: BoxDecoration( color: Colors.black, border: Border.all( color: controller != null && controller!.value.isRecordingVideo ? Colors.redAccent : Colors.grey, width: controller != null && controller!.value.isRecordingVideo ? 1.0 : 0.0, ), ), ), ), _captureControlRowWidget(), ], ), ), ); } /// Display the preview from the camera (or a message if the preview is not available). Widget _cameraPreviewWidget() { if (controller == null || !controller!.value.isInitialized) { return const Text( 'Đang mở camera ....', style: TextStyle( color: Colors.white, fontSize: 18.0, fontWeight: FontWeight.w900, ), ); } else { return AspectRatio( aspectRatio: controller!.value.aspectRatio, child: CameraPreview(controller!), ); } } /// Display the control bar with buttons to take pictures and record videos. Widget _captureControlRowWidget() { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisSize: MainAxisSize.max, children: [ IconButton( icon: Icon(Icons.arrow_back), onPressed: () { Get.back(); }), _cameraTogglesRowWidget(), IconButton( icon: const Icon( Icons.camera_alt, size: 30, ), color: Colors.blue, onPressed: controller != null && controller!.value.isInitialized && !controller!.value.isRecordingVideo ? onTakePictureButtonPressed : null, ), // IconButton( // icon: const Icon(Icons.videocam, size: 35), // color: Colors.blue, // onPressed: controller != null && controller.value.isInitialized && !controller.value.isRecordingVideo ? onVideoRecordButtonPressed : null, // ), // IconButton( // icon: controller != null && controller.value.isRecordingPaused ? Icon(Icons.play_arrow) : Icon(Icons.pause), // color: Colors.blue, // onPressed: controller != null && controller.value.isInitialized && controller.value.isRecordingVideo // ? (controller != null && controller.value.isRecordingPaused ? onResumeButtonPressed : onPauseButtonPressed) // : null, // ), // IconButton( // icon: const Icon(Icons.stop), // color: Colors.red, // onPressed: controller != null && controller.value.isInitialized && controller.value.isRecordingVideo ? onStopButtonPressed : null, // ) ], ); } /// Display a row of toggle to select the camera (or a message if no camera is available). Widget _cameraTogglesRowWidget() { if (cameras.isEmpty) { return const Text('Không có camera'); } else { bool disableSwitch = controller != null && controller!.value.isRecordingVideo; if (indexCamera == cameras.length - 1) { indexCamera = 0; } else { indexCamera++; } return IconButton( icon: Icon( Icons.switch_camera, color: Colors.green, ), onPressed: disableSwitch == true ? null : () { onNewCameraSelected(cameras[indexCamera]); }); } } String timestamp() => DateTime.now().millisecondsSinceEpoch.toString(); void showInSnackBar(String message) { Utils.showSnackBarError(message: message); } void onNewCameraSelected(CameraDescription cameraDescription) async { if (controller != null) { await controller?.dispose(); } controller = CameraController( cameraDescription, ResolutionPreset.medium, enableAudio: enableAudio, ); // If the controller is updated then update the UI. controller?.addListener(() { if (mounted) setState(() {}); if (controller!.value.hasError) { showInSnackBar('Lỗi camera: ${controller?.value.errorDescription}'); } }); try { await controller?.initialize(); } on CameraException catch (e) { _showCameraException(e); } if (mounted) { setState(() {}); } } void onTakePictureButtonPressed() { takePicture().then((String filePath) { if (mounted) { setState(() { imagePath = filePath; // videoController?.dispose(); // videoController = null; }); if (filePath != null) { print('Picture saved to $filePath'); Get.back(result: [filePath, false]); } } }); } void onVideoRecordButtonPressed() { startVideoRecording().then((String filePath) { if (mounted) setState(() {}); if (filePath != null) { print('Saving video to $filePath'); } }); } void onStopButtonPressed() { stopVideoRecording().then((_) { if (mounted) setState(() {}); { print('Video recorded to: $videoPath'); Get.back(result: [videoPath, true]); } }); } void onPauseButtonPressed() { pauseVideoRecording().then((_) { if (mounted) setState(() {}); print('Video recording paused'); }); } void onResumeButtonPressed() { resumeVideoRecording().then((_) { if (mounted) setState(() {}); print('Video recording resumed'); }); } Future startVideoRecording() async { if (!controller!.value.isInitialized) { showInSnackBar('Vui lòng chọn camera'); return ''; } final Directory extDir = await getApplicationDocumentsDirectory(); final String dirPath = '${extDir.path}/Movies/tpf'; await Directory(dirPath).create(recursive: true); final String filePath = '$dirPath/${timestamp()}.mp4'; if (controller!.value.isRecordingVideo) { // A recording is already started, do nothing. return ''; } try { videoPath = filePath; // await controller?.startVideoRecording(filePath ?? ''); } on CameraException catch (e) { _showCameraException(e); return ''; } return filePath; } Future stopVideoRecording() async { if (!controller!.value.isRecordingVideo) { return null; } try { await controller?.stopVideoRecording(); } on CameraException catch (e) { _showCameraException(e); return null; } } Future pauseVideoRecording() async { if (!controller!.value.isRecordingVideo) { return null; } try { await controller?.pauseVideoRecording(); } on CameraException catch (e) { _showCameraException(e); rethrow; } } Future resumeVideoRecording() async { if (!controller!.value.isRecordingVideo) { return null; } try { await controller?.resumeVideoRecording(); } on CameraException catch (e) { _showCameraException(e); rethrow; } } Future takePicture() async { if (!controller!.value.isInitialized) { showInSnackBar('Vui lòng chọn camera'); return ''; } final Directory extDir = await getApplicationDocumentsDirectory(); final String dirPath = '${extDir.path}/Pictures/tpf'; await Directory(dirPath).create(recursive: true); String filePath = '$dirPath/${timestamp()}.jpg'; if (controller!.value.isTakingPicture) { // A capture is already pending, do nothing. return ''; } try { var xFile = await controller?.takePicture(); //.takePicture(filePath); filePath = xFile?.path ?? ''; } on CameraException catch (e) { _showCameraException(e); return ''; } return filePath; } void _showCameraException(CameraException e) { logError(e.code, e.description ?? ''); showInSnackBar('Lỗi: ${e.code}\n${e.description}'); } }