import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/utils/debouncer.dart'; import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart'; import 'package:flux/features/notes/blocs/notes_bloc.dart'; import 'package:flux/features/notes/models/note_model.dart'; class NoteFormScreen extends StatefulWidget { final NoteModel note; // La nota DEVE essere già stata creata (anche vuota) dal DB prima di arrivare qui const NoteFormScreen({super.key, required this.note}); @override State createState() => _NoteFormScreenState(); } class _NoteFormScreenState extends State { NoteModel get _note => widget.note; late TextEditingController _titleController; late TextEditingController _contentController; late final NotesBloc _notesBloc; late String _selectedColor; late bool _isPinned; late bool _isSharedAll; late List _selectedStaffIds; // Inizializziamo il Debouncer a 500 millisecondi final _debouncer = Debouncer(milliseconds: 500); final List _noteColors = [ '#FFF59D', '#FFCDD2', '#C8E6C9', '#BBDEFB', '#E1BEE7', '#F5F5F5', ]; @override void initState() { super.initState(); _titleController = TextEditingController(text: widget.note.title ?? ''); _contentController = TextEditingController(text: widget.note.content ?? ''); _notesBloc = context.read(); _selectedColor = widget.note.color; _isPinned = widget.note.isPinned; _isSharedAll = widget.note.isSharedAll; _selectedStaffIds = List.from(widget.note.collaboratorIds); // Mettiamo i controller in ascolto per scatenare l'auto-salvataggio _titleController.addListener(_onFieldsChanged); _contentController.addListener(_onFieldsChanged); } @override void dispose() { _titleController.removeListener(_onFieldsChanged); _contentController.removeListener(_onFieldsChanged); _titleController.dispose(); _contentController.dispose(); _debouncer.dispose(); // --- IL BOTTO FINALE: PULIZIA SILENZIOSA --- _checkAndCleanupIfEmpty(_note.id!); super.dispose(); } /// Chiamata ogni volta che l'utente digita una lettera void _onFieldsChanged() { _debouncer.run(() => _triggerAutoSave()); } /// Salva in background notificando il BLoC (così la bacheca si aggiorna in tempo reale) void _triggerAutoSave() { final companyId = context.read().state.company!.id!; final updatedNote = NoteModel( id: widget.note.id, createdBy: widget.note.createdBy, companyId: companyId, title: _titleController.text.trim(), content: _contentController.text.trim(), color: _selectedColor, isPinned: _isPinned, isSharedAll: _isSharedAll, collaboratorIds: _selectedStaffIds, ); // Spariamo l'evento al Bloc, che salverà silente sul DB tramite Repository _notesBloc.add(NoteSavedRequested(updatedNote)); } /// Se l'utente esce e la nota è totalmente vuota, la eliminiamo dal DB "al secchio" void _checkAndCleanupIfEmpty(String noteId) { final titleEmpty = _titleController.text.trim().isEmpty; final contentEmpty = _contentController.text.trim().isEmpty; //Se hai un modo per verificare se ci sono allegati associati (es. tramite una query locale o un contatore), // assicurati che non ce ne siano prima di eliminare. // Assumiamo che se non ha scritto testo ed è appena stata creata, sia vuota. if (titleEmpty && contentEmpty) { // Notifichiamo anche il Bloc dell'avvenuta cancellazione così pulisce lo stato locale _notesBloc.add(NoteDeletedRequested(noteId)); } } void _deleteNote() { _notesBloc.add(NoteDeletedRequested(widget.note.id!)); Navigator.pop(context); } void _exportNote() { // La logica di export che abbiamo concordato ieri! ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Funzione di esportazione/stampa in arrivo! 🚀'), ), ); } void _showStaffPickerBottomSheet() { final allStaff = context.read().state.storeStaff; // Recuperiamo l'ID del creatore della nota final creatorId = widget.note.createdBy; showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) { return StatefulBuilder( builder: (context, setModalState) { return Column( children: [ Padding( padding: const EdgeInsets.all(16.0), child: Text( 'Seleziona Collaboratori', style: Theme.of(context).textTheme.titleLarge, ), ), Expanded( child: ListView.builder( itemCount: allStaff.length, itemBuilder: (context, index) { final staff = allStaff[index]; // Capiamo se questo membro dello staff è il creatore final isCreator = staff.id == creatorId; // È spuntato se è il creatore OPPURE se è nella lista dei collaboratori final isSelected = isCreator || _selectedStaffIds.contains(staff.id); return CheckboxListTile( title: RichText( text: TextSpan( style: Theme.of(context).textTheme.bodyLarge, children: [ TextSpan(text: staff.name), if (isCreator) const TextSpan( text: ' (Proprietario)', style: TextStyle( color: Colors.grey, fontStyle: FontStyle.italic, fontSize: 12, ), ), ], ), ), value: isSelected, activeColor: Theme.of(context).colorScheme.primary, // IL TRUCCO NINJA: se è il creatore, passiamo null per disabilitare la spunta! onChanged: isCreator ? null : (bool? value) { setModalState(() { if (value == true) { _selectedStaffIds.add(staff.id!); } else { _selectedStaffIds.remove(staff.id!); } }); setState(() {}); _triggerAutoSave(); }, ); }, ), ), Padding( padding: const EdgeInsets.all(16.0), child: FilledButton( onPressed: () => Navigator.pop(context), child: const Text('Fatto'), ), ), ], ); }, ); }, ); } @override Widget build(BuildContext context) { final noteColor = Color( int.parse('FF${_selectedColor.replaceAll('#', '')}', radix: 16), ); return Scaffold( // 1. Sfondo scuro e riposante per l'intera schermata backgroundColor: Colors.grey.shade900, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, // Freccia indietro chiara per fare contrasto sullo sfondo grigio scuro iconTheme: const IconThemeData(color: Colors.white70), ), body: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 680), child: SingleChildScrollView( padding: const EdgeInsets.only(bottom: 64, left: 16, right: 16), child: Container( // 2. IL NOSTRO POST-IT FISICO decoration: BoxDecoration( color: noteColor, borderRadius: BorderRadius.circular(16), // Bordi arrotondati boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.4), // Ombra morbida blurRadius: 24, offset: const Offset(0, 12), ), ], ), padding: const EdgeInsets.all(24.0), child: Column( // 3. MainAxisSize.min fa sì che il Post-it sia alto solo quanto serve! mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // --- HEADER DEL POST-IT (Tavolozza + Azioni) --- Row( children: [ // Tavolozza Colori Expanded( child: SizedBox( height: 40, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: _noteColors.length, itemBuilder: (context, index) { final colorHex = _noteColors[index]; final isSelected = _selectedColor == colorHex; final c = Color( int.parse( 'FF${colorHex.replaceAll('#', '')}', radix: 16, ), ); return GestureDetector( onTap: () { setState(() => _selectedColor = colorHex); _triggerAutoSave(); }, child: Container( margin: const EdgeInsets.only(right: 12), width: 40, decoration: BoxDecoration( color: c, shape: BoxShape.circle, border: Border.all( color: isSelected ? Colors.black54 : Colors.black12, width: isSelected ? 3 : 1, ), ), child: isSelected ? const Icon( Icons.check, color: Colors.black54, size: 20, ) : null, ), ); }, ), ), ), const SizedBox(width: 16), // Azioni spostate dentro la nota! IconButton( icon: const Icon( Icons.delete_outline, color: Colors.black87, ), tooltip: 'Elimina', onPressed: _deleteNote, ), IconButton( icon: Icon( _isPinned ? Icons.push_pin : Icons.push_pin_outlined, color: Colors.black87, ), tooltip: _isPinned ? 'Rimuovi in alto' : 'Fissa in alto', onPressed: () { setState(() => _isPinned = !_isPinned); _triggerAutoSave(); }, ), IconButton( icon: const Icon( Icons.ios_share, color: Colors.black87, ), tooltip: 'Esporta', onPressed: _exportNote, ), ], ), const SizedBox(height: 32), // --- TITOLO --- TextFormField( controller: _titleController, style: const TextStyle( fontSize: 28, fontWeight: FontWeight.bold, color: Colors.black87, ), decoration: const InputDecoration( hintText: 'Titolo...', hintStyle: TextStyle(color: Colors.black38), border: InputBorder.none, ), ), // --- CONTENUTO --- TextFormField( controller: _contentController, style: const TextStyle( fontSize: 18, color: Colors.black87, height: 1.5, ), maxLines: null, minLines: 12, decoration: const InputDecoration( hintText: 'Scrivi qui la tua nota...', hintStyle: TextStyle(color: Colors.black38), border: InputBorder.none, ), ), const SizedBox(height: 24), const Divider(color: Colors.black12), const SizedBox(height: 12), // --- CONDIVISIONE --- SwitchListTile( title: const Text( 'Condividi con tutti', style: TextStyle( color: Colors.black87, fontWeight: FontWeight.w500, ), ), value: _isSharedAll, activeThumbColor: Colors.black87, contentPadding: EdgeInsets.zero, onChanged: (val) { setState(() { _isSharedAll = val; if (val) _selectedStaffIds.clear(); }); _triggerAutoSave(); }, ), if (!_isSharedAll) ...[ const SizedBox(height: 16), Wrap( spacing: 8.0, runSpacing: 8.0, children: [ ActionChip( avatar: const Icon( Icons.add, size: 18, color: Colors.white, ), label: const Text( 'Aggiungi Colleghi', style: TextStyle( color: Colors.white, fontWeight: FontWeight.w600, ), ), onPressed: _showStaffPickerBottomSheet, // Pesca in automatico il blu dei tuoi pulsanti Salva! backgroundColor: Theme.of( context, ).colorScheme.primary, side: BorderSide .none, // Togliamo il bordino per un look più pulito e solido elevation: 2, // Una leggera ombra per farlo sembrare cliccabile ), if (_selectedStaffIds.isNotEmpty) Chip( label: Text( '${_selectedStaffIds.length} collaboratori', style: const TextStyle(color: Colors.black87), ), backgroundColor: Colors.white.withValues( alpha: 0.6, ), deleteIconColor: Colors.black87, side: const BorderSide(color: Colors.black12), onDeleted: () { setState(() => _selectedStaffIds.clear()); _triggerAutoSave(); }, ), ], ), ], const SizedBox(height: 24), const Divider(color: Colors.black12), const SizedBox(height: 24), // --- ALLEGATI --- // SharedAttachmentsSection( // parentType: AttachmentParentType.note, // parentId: widget.note.id!, // ), ], ), ), ), ), ), ); } }