import 'dart:typed_data'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:geolocator/geolocator.dart'; import 'package:image_picker/image_picker.dart'; import 'package:file_picker/file_picker.dart'; import '../../../core/utils/hash_utils.dart'; import '../../../data/repositories/contenedor_repository.dart'; import '../../../domain/entities/archivo_adjunto.dart'; import '../../../domain/entities/contenedor.dart'; import '../../../domain/entities/destino.dart'; import '../../../domain/entities/gps_location.dart'; import 'captura_state.dart'; class CapturaCubit extends Cubit { final ContenedorRepository _repo = ContenedorRepository(); final ImagePicker _picker = ImagePicker(); CapturaCubit() : super(CapturaState( contenedor: Contenedor(hash: HashUtils.generateHash()), )); void regenerateHash() { emit(state.copyWith( contenedor: state.contenedor.copyWith(hash: HashUtils.generateHash()), )); } void setTitulo(String titulo) { emit(state.copyWith( contenedor: state.contenedor.copyWith(titulo: titulo.isEmpty ? null : titulo), )); } void setDescripcion(String descripcion) { emit(state.copyWith( contenedor: state.contenedor.copyWith( descripcion: descripcion.isEmpty ? null : descripcion, ), )); } Future capturePhoto() async { try { final image = await _picker.pickImage(source: ImageSource.camera); if (image == null) return; final bytes = await image.readAsBytes(); final archivo = ArchivoAdjunto( nombre: image.name, mimeType: 'image/jpeg', bytes: bytes, tipo: ArchivoTipo.image, hash: HashUtils.hashFromBytes(bytes), ); emit(state.addArchivo(archivo)); } catch (e) { emit(state.copyWith( status: CapturaStatus.error, errorMessage: 'Error al capturar foto: $e', )); } } Future captureVideo() async { try { final video = await _picker.pickVideo(source: ImageSource.camera); if (video == null) return; final bytes = await video.readAsBytes(); final archivo = ArchivoAdjunto( nombre: video.name, mimeType: 'video/mp4', bytes: bytes, tipo: ArchivoTipo.video, hash: HashUtils.hashFromBytes(bytes), ); emit(state.addArchivo(archivo)); } catch (e) { emit(state.copyWith( status: CapturaStatus.error, errorMessage: 'Error al capturar video: $e', )); } } Future pickFile() async { try { final result = await FilePicker.platform.pickFiles(withData: true); if (result == null || result.files.isEmpty) return; final file = result.files.first; if (file.bytes == null) return; final archivo = ArchivoAdjunto( nombre: file.name, mimeType: _getMimeType(file.extension), bytes: file.bytes!, tipo: ArchivoTipo.document, hash: HashUtils.hashFromBytes(file.bytes!), ); emit(state.addArchivo(archivo)); } catch (e) { emit(state.copyWith( status: CapturaStatus.error, errorMessage: 'Error al seleccionar archivo: $e', )); } } void addAudioFile(Uint8List bytes, String nombre) { final archivo = ArchivoAdjunto( nombre: nombre, mimeType: 'audio/m4a', bytes: bytes, tipo: ArchivoTipo.audio, hash: HashUtils.hashFromBytes(bytes), ); emit(state.addArchivo(archivo)); } void removeArchivo(int index) { emit(state.removeArchivo(index)); } Future captureGps() async { try { final permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { await Geolocator.requestPermission(); } final position = await Geolocator.getCurrentPosition(); final gps = GpsLocation(lat: position.latitude, long: position.longitude); emit(state.setGps(gps)); } catch (e) { emit(state.copyWith( status: CapturaStatus.error, errorMessage: 'Error al obtener GPS: $e', )); } } void clearGps() { emit(state.setGps(null)); } void setEtiquetas(List etiquetas) { emit(state.setEtiquetas(etiquetas)); } Future enviar(Destino destino) async { emit(state.copyWith(status: CapturaStatus.sending)); try { await _repo.enviar(state.contenedor, destino); emit(state.copyWith(status: CapturaStatus.success)); reset(); } catch (e) { emit(state.copyWith( status: CapturaStatus.error, errorMessage: 'Error al enviar: $e', )); } } void reset() { emit(CapturaState( contenedor: Contenedor(hash: HashUtils.generateHash()), )); } String _getMimeType(String? extension) { switch (extension?.toLowerCase()) { case 'pdf': return 'application/pdf'; case 'doc': case 'docx': return 'application/msword'; case 'xls': case 'xlsx': return 'application/vnd.ms-excel'; case 'png': return 'image/png'; case 'jpg': case 'jpeg': return 'image/jpeg'; default: return 'application/octet-stream'; } } }