import 'package:camera/camera.dart'; import 'package:file_picker/file_picker.dart'; import 'package:file_selector/file_selector.dart' as file_selector; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:votianlt_app/services/developer.dart' as developer; import '../l10n/app_localizations.dart'; class ChatPhotoDialog extends StatefulWidget { const ChatPhotoDialog({super.key}); @override State createState() => _ChatPhotoDialogState(); } class _ChatPhotoDialogState extends State { CameraController? _cameraController; bool _isCameraInitialized = false; bool _useCamera = false; bool _useFilePicker = false; bool _isBusy = false; Uint8List? _previewBytes; String? _errorMessage; @override void initState() { super.initState(); _detectAndInit(); } @override void dispose() { _cameraController?.dispose(); super.dispose(); } Future _detectAndInit() async { if (kIsWeb) { setState(() { _useCamera = true; _useFilePicker = true; }); await _initializeCamera(); return; } switch (defaultTargetPlatform) { case TargetPlatform.android: case TargetPlatform.iOS: setState(() { _useCamera = true; _useFilePicker = true; }); await _initializeCamera(); return; case TargetPlatform.macOS: case TargetPlatform.windows: case TargetPlatform.linux: setState(() { _useFilePicker = true; }); return; default: setState(() { _errorMessage = 'Dieses Gerät unterstützt keine Fotoaufnahme.'; }); } } Future _initializeCamera() async { try { final cameras = await availableCameras(); if (cameras.isEmpty) { setState(() { _errorMessage = 'Keine Kamera gefunden.'; }); return; } final controller = CameraController( cameras.first, ResolutionPreset.medium, enableAudio: false, ); await controller.initialize(); if (!mounted) { await controller.dispose(); return; } setState(() { _cameraController = controller; _isCameraInitialized = true; }); } catch (e, stackTrace) { developer.log( 'Fehler beim Initialisieren der Kamera: $e', name: 'ChatPhotoDialog', ); developer.log('StackTrace: $stackTrace', name: 'ChatPhotoDialog'); if (!mounted) { return; } setState(() { _errorMessage = 'Kamera konnte nicht gestartet werden.'; }); } } Future _capturePhoto() async { if (_cameraController == null || !_cameraController!.value.isInitialized) { setState(() { _errorMessage = 'Kamera ist nicht bereit.'; }); return; } try { setState(() { _isBusy = true; _errorMessage = null; }); final XFile photo = await _cameraController!.takePicture(); final Uint8List bytes = await photo.readAsBytes(); if (!mounted) { return; } setState(() { _previewBytes = bytes; }); } catch (e, stackTrace) { developer.log( 'Fehler beim Aufnehmen des Fotos: $e', name: 'ChatPhotoDialog', ); developer.log('StackTrace: $stackTrace', name: 'ChatPhotoDialog'); if (!mounted) { return; } setState(() { _errorMessage = 'Foto konnte nicht aufgenommen werden.'; }); } finally { if (mounted) { setState(() { _isBusy = false; }); } } } Future _pickPhotoFromFile() async { try { setState(() { _isBusy = true; _errorMessage = null; }); if (kIsWeb || defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.windows || defaultTargetPlatform == TargetPlatform.linux) { final group = file_selector.XTypeGroup( label: 'images', extensions: ['jpg', 'jpeg', 'png', 'heic', 'bmp', 'gif', 'webp'], ); final file = await file_selector.openFile(acceptedTypeGroups: [group]); if (file == null) { return; } final bytes = await file.readAsBytes(); if (!mounted) { return; } setState(() { _previewBytes = bytes; }); return; } final result = await FilePicker.platform.pickFiles( allowMultiple: false, type: FileType.image, withData: true, ); if (result == null || result.files.isEmpty) { return; } final picked = result.files.first; final bytes = picked.bytes; if (bytes == null) { setState(() { _errorMessage = 'Die ausgewählte Datei konnte nicht gelesen werden.'; }); return; } if (!mounted) { return; } setState(() { _previewBytes = bytes; }); } catch (e, stackTrace) { developer.log( 'Fehler beim Auswählen eines Fotos: $e', name: 'ChatPhotoDialog', ); developer.log('StackTrace: $stackTrace', name: 'ChatPhotoDialog'); if (!mounted) { return; } setState(() { _errorMessage = 'Foto konnte nicht geladen werden.'; }); } finally { if (mounted) { setState(() { _isBusy = false; }); } } } void _resetPreview() { setState(() { _previewBytes = null; }); } @override Widget build(BuildContext context) { return AlertDialog( title: Text(AppLocalizations.of(context).takePhoto), content: SizedBox(width: 320, child: _buildDialogBody()), actions: [ TextButton( onPressed: _isBusy ? null : () => Navigator.of(context).pop(), child: Text(AppLocalizations.of(context).cancel), ), TextButton( onPressed: _previewBytes != null && !_isBusy ? () => Navigator.of(context).pop(_previewBytes) : null, child: Text(AppLocalizations.of(context).send), ), ], ); } Widget _buildDialogBody() { if (_previewBytes != null) { return Column( mainAxisSize: MainAxisSize.min, children: [ AspectRatio( aspectRatio: 4 / 3, child: ClipRRect( borderRadius: BorderRadius.circular(12), child: Image.memory(_previewBytes!, fit: BoxFit.cover), ), ), const SizedBox(height: 12), TextButton.icon( onPressed: _isBusy ? null : _resetPreview, icon: const Icon(Icons.refresh), label: Text(AppLocalizations.of(context).retakePhoto), ), ], ); } if (_errorMessage != null) { return Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.warning, color: Colors.orange[700], size: 40), const SizedBox(height: 12), Text(_errorMessage!, textAlign: TextAlign.center), ], ); } if (_useCamera) { if (!_isCameraInitialized) { return const SizedBox( height: 200, child: Center(child: CircularProgressIndicator()), ); } return Column( mainAxisSize: MainAxisSize.min, children: [ AspectRatio( aspectRatio: _cameraController?.value.aspectRatio ?? (3 / 4), child: ClipRRect( borderRadius: BorderRadius.circular(12), child: CameraPreview(_cameraController!), ), ), const SizedBox(height: 12), Wrap( alignment: WrapAlignment.center, spacing: 8, runSpacing: 8, children: [ ElevatedButton.icon( onPressed: _isBusy ? null : _capturePhoto, icon: const Icon(Icons.camera_alt), label: Text(AppLocalizations.of(context).takePhoto), ), if (_useFilePicker) OutlinedButton.icon( onPressed: _isBusy ? null : _pickPhotoFromFile, icon: const Icon(Icons.photo_library), label: Text(AppLocalizations.of(context).selectFromLibrary), ), ], ), ], ); } if (_useFilePicker) { return Column( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.photo_camera_back, color: Colors.deepPurple[400], size: 48, ), const SizedBox(height: 12), const Text( 'Wähle ein Foto von deinem Gerät aus.', textAlign: TextAlign.center, ), const SizedBox(height: 12), ElevatedButton.icon( onPressed: _isBusy ? null : _pickPhotoFromFile, icon: const Icon(Icons.photo_library), label: Text(AppLocalizations.of(context).selectPhoto), ), ], ); } return const SizedBox( height: 160, child: Center(child: CircularProgressIndicator()), ); } }