import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flux/core/routes/routes.dart'; import 'package:flux/features/notes/blocs/notes_bloc.dart'; import 'package:flux/features/notes/data/notes_repository.dart'; import 'package:go_router/go_router.dart'; import 'package:get_it/get_it.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/features/notes/models/note_model.dart'; class NotesListScreen extends StatelessWidget { const NotesListScreen({super.key}); /// Logica Ninja: Crea la nota vuota, prende l'ID, e apre il form Future _createNewNoteAndNavigate(BuildContext context) async { final sessionState = context.read().state; final companyId = sessionState.company!.id!; final currentStaffId = sessionState.currentStaffMember!.id!; // 1. Creiamo la nota vuota final emptyNote = NoteModel.empty( createdBy: currentStaffId, companyId: companyId, ).copyWith(color: '#FFF59D'); // Mostriamo un loading veloce se serve (opzionale) ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Creazione nota in corso...'), duration: Duration(milliseconds: 500), ), ); try { // 2. Scriviamo su DB per avere l'ID final noteId = await GetIt.I.get().saveNote(emptyNote); if (context.mounted) { // 3. Spingiamo l'utente nel form con la nota già provvista di ID! context.pushNamed( Routes.noteForm, pathParameters: ({'id': noteId}), extra: emptyNote.copyWith(id: noteId), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Errore: Impossibile creare la nota. $e')), ); } } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey.shade50, // Sfondo neutro per far risaltare i post-it appBar: AppBar( title: const Text( 'Bacheca Note', style: TextStyle(fontWeight: FontWeight.bold), ), centerTitle: false, backgroundColor: Colors.transparent, elevation: 0, ), floatingActionButton: FloatingActionButton.extended( onPressed: () => _createNewNoteAndNavigate(context), icon: const Icon(Icons.add), label: const Text('Nuova Nota'), backgroundColor: Theme.of(context).colorScheme.primary, foregroundColor: Colors.white, ), body: BlocBuilder( builder: (context, state) { if (state.status == NotesStatus.loading && state.notes.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (state.status == NotesStatus.failure) { return Center( child: Text( 'Errore nel caricamento: ${state.errorMessage}', style: const TextStyle(color: Colors.red), ), ); } if (state.notes.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.sticky_note_2_outlined, size: 64, color: Colors.grey.shade400, ), const SizedBox(height: 16), Text( 'Nessuna nota presente.', style: TextStyle(color: Colors.grey.shade600, fontSize: 18), ), const SizedBox(height: 8), const Text('Clicca su "Nuova Nota" per iniziare.'), ], ), ); } // Ordiniamo le note: prima le pinnate, poi le altre (se non le ordina già il DB) final sortedNotes = List.from(state.notes) ..sort((a, b) { if (a.isPinned && !b.isPinned) return -1; if (!a.isPinned && b.isPinned) return 1; return 0; // Se vuoi puoi aggiungere l'ordinamento per data qui }); return _buildMasonryGrid(context, sortedNotes); }, ), ); } Widget _buildMasonryGrid(BuildContext context, List notes) { // Calcoliamo quante colonne mostrare in base alla larghezza dello schermo final screenWidth = MediaQuery.of(context).size.width; int crossAxisCount = 2; // Mobile if (screenWidth > 600) crossAxisCount = 3; // Tablet if (screenWidth > 900) crossAxisCount = 4; // Desktop piccolo if (screenWidth > 1200) crossAxisCount = 5; // Desktop grande return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: MasonryGridView.count( crossAxisCount: crossAxisCount, mainAxisSpacing: 12, crossAxisSpacing: 12, itemCount: notes.length, padding: const EdgeInsets.only( bottom: 80, top: 8, ), // Spazio per non coprire col FAB itemBuilder: (context, index) { final note = notes[index]; return _buildNoteCard(context, note); }, ), ); } Widget _buildNoteCard(BuildContext context, NoteModel note) { final noteColor = Color( int.parse('FF${note.color.replaceAll('#', '')}', radix: 16), ); return GestureDetector( onTap: () => context.push('/notes/edit', extra: note), child: Container( decoration: BoxDecoration( color: noteColor, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.1), blurRadius: 4, offset: const Offset(2, 2), ), ], border: Border.all(color: Colors.black.withValues(alpha: 0.05)), ), padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, // Fondamentale per il Masonry! children: [ if (note.title != null && note.title!.isNotEmpty) ...[ Text( note.title!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, color: Colors.black87, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 8), ], if (note.content != null && note.content!.isNotEmpty) ...[ Text( note.content!, style: const TextStyle( fontSize: 14, color: Colors.black87, height: 1.3, ), // Limitiamo le righe in bacheca per non avere post-it lunghi 3 metri maxLines: 8, overflow: TextOverflow.ellipsis, ), ], // Footer con icone di stato (Pin, Condivisione, Allegati) _buildCardFooter(note), ], ), ), ); } Widget _buildCardFooter(NoteModel note) { final hasStatusIcons = note.isPinned || note.isSharedAll || note.collaboratorIds.isNotEmpty; if (!hasStatusIcons) return const SizedBox.shrink(); return Padding( padding: const EdgeInsets.only(top: 12.0), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ if (note.isSharedAll || note.collaboratorIds.isNotEmpty) const Padding( padding: EdgeInsets.only(right: 8.0), child: Icon( Icons.people_alt_outlined, size: 16, color: Colors.black54, ), ), const Padding( padding: EdgeInsets.only(right: 8.0), child: Icon(Icons.attachment, size: 16, color: Colors.black54), ), if (note.isPinned) const Icon(Icons.push_pin, size: 16, color: Colors.black54), ], ), ); } }