import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/features/operations/blocs/operations_cubit.dart'; import 'package:flux/features/operations/models/operation_model.dart'; import 'package:go_router/go_router.dart'; // Importa i tuoi modelli e cubit class OperationsScreen extends StatefulWidget { const OperationsScreen({super.key}); @override State createState() => _OperationsScreenState(); } class _OperationsScreenState extends State { final ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); // Agganciamo il listener per la paginazione (Scroll Infinito) _scrollController.addListener(_onScroll); // Carichiamo i servizi iniziali context.read().loadOperations(); } void _onScroll() { if (_isBottom) { context.read().loadOperations(); } } bool get _isBottom { if (!_scrollController.hasClients) return false; final maxScroll = _scrollController.position.maxScrollExtent; final currentScroll = _scrollController.offset; // Carica quando mancano 200px alla fine return currentScroll >= (maxScroll * 0.9); } @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Gestione Servizi"), elevation: 0, actions: [ IconButton( icon: const Icon(Icons.search), onPressed: () { // Qui potrai implementare una barra di ricerca }, ), ], ), body: BlocBuilder( builder: (context, state) { // 1. Stato di caricamento iniziale if (state.status == OperationsStatus.loading && state.allOperations.isEmpty) { return const Center(child: CircularProgressIndicator()); } // 2. Lista vuota if (state.allOperations.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("Nessuna pratica trovata."), const SizedBox(height: 10), ElevatedButton( onPressed: () => context .read() .loadOperations(refresh: true), child: const Text("Riprova"), ), ], ), ); } // 3. La Lista (con Pull-to-refresh) return RefreshIndicator( onRefresh: () => context.read().loadOperations(refresh: true), child: ListView.builder( controller: _scrollController, padding: const EdgeInsets.only(bottom: 80), // Spazio per il FAB itemCount: state.hasReachedMax ? state.allOperations.length : state.allOperations.length + 1, itemBuilder: (context, index) { if (index >= state.allOperations.length) { return const Center( child: Padding( padding: EdgeInsets.all(16.0), child: CircularProgressIndicator(strokeWidth: 2), ), ); } final operation = state.allOperations[index]; return _buildOperationCard(context, operation); }, ), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () => startNewOperation(context), child: const Icon(Icons.add), ), ); } Widget _buildOperationCard(BuildContext context, OperationModel operation) { return Card( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), elevation: 2, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: ListTile( contentPadding: const EdgeInsets.all(12), title: Row( children: [ Expanded( child: Text( operation.customerDisplayName ?? "Cliente sconosciuto", style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), ), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 4), Text( "Pratica: ${operation.reference} • ${operation.createdAt?.day}/${operation.createdAt?.month}/${operation.createdAt?.year}", ), const SizedBox(height: 8), Row( children: [ Text(operation.type), const SizedBox(width: 8), _buildOperationStatus(operation.status), ], ), ], ), trailing: const Icon(Icons.chevron_right), onTap: () => context.pushNamed( 'operation-form', extra: operation, // <-- LA MAGIA È QUI: Passa l'oggetto intero! // Teniamo anche il parametro URL per coerenza di routing queryParameters: operation.id != null ? {'operationId': operation.id!} : {}, ), ), ); } Widget _buildOperationStatus(OperationStatus status) { Color color; switch (status) { case OperationStatus.canceled || OperationStatus.ko: color = Colors.grey.shade800; break; case OperationStatus.waitingforaction || OperationStatus.draft: color = Colors.orange; break; case OperationStatus.ok: color = Colors.green; break; case OperationStatus.waitingfordeployment || OperationStatus.waitingforsupport: color = Colors.blue; break; } return Chip( label: Text("BOZZA", style: TextStyle(fontSize: 10, color: Colors.white)), backgroundColor: color, visualDensity: VisualDensity.compact, ); } void startNewOperation(BuildContext context) { context.pushNamed('operation-form'); } }