import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:intl/intl.dart'; import '../models/sito.dart'; import '../models/allarme.dart'; import '../services/api_service.dart'; import '../widgets/allarme_card.dart'; import '../utils/constants.dart'; class SitoDetailScreen extends StatefulWidget { final Sito sito; const SitoDetailScreen({super.key, required this.sito}); @override State createState() => _SitoDetailScreenState(); } class _SitoDetailScreenState extends State with SingleTickerProviderStateMixin { final _apiService = ApiService(); List _allarmi = []; bool _isLoadingAllarmi = true; String? _errorMessage; late TabController _tabController; GoogleMapController? _mapController; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); _loadAllarmi(); } @override void dispose() { _tabController.dispose(); _mapController?.dispose(); super.dispose(); } Future _loadAllarmi() async { try { final response = await _apiService.getAllarmiBySito(widget.sito.id); setState(() { _allarmi = response.items; _isLoadingAllarmi = false; }); } catch (e) { setState(() { _errorMessage = 'Errore caricamento allarmi: $e'; _isLoadingAllarmi = false; }); } } Color _getTipoColor() { switch (widget.sito.tipo) { case 'ponte': return Colors.blue; case 'galleria': return Colors.brown; case 'diga': return Colors.cyan; case 'frana': return Colors.orange; case 'versante': return Colors.green; case 'edificio': return Colors.purple; default: return AppColors.primary; } } IconData _getTipoIcon() { switch (widget.sito.tipo) { case 'ponte': return Icons.architecture; case 'galleria': return Icons.south_west; case 'diga': return Icons.water_damage; case 'frana': return Icons.landscape; case 'versante': return Icons.terrain; case 'edificio': return Icons.business; default: return Icons.location_on; } } int get _allarmiCritici => _allarmi.where((a) => a.severita == 'critical').length; int get _allarmiAperti => _allarmi.where((a) => a.stato != 'risolto').length; @override Widget build(BuildContext context) { final dateFormat = DateFormat('dd/MM/yyyy'); return Scaffold( body: NestedScrollView( headerSliverBuilder: (context, innerBoxIsScrolled) { return [ SliverAppBar( expandedHeight: 180, pinned: true, flexibleSpace: FlexibleSpaceBar( background: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ _getTipoColor(), _getTipoColor().withOpacity(0.7), ], ), ), child: SafeArea( child: Padding( padding: const EdgeInsets.fromLTRB( AppSizes.paddingL, AppSizes.paddingL, AppSizes.paddingL, 70, // Spazio per le tab (altezza standard tab bar) ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.end, children: [ Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Icon( _getTipoIcon(), size: 32, color: _getTipoColor(), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.sito.tipoReadable, style: TextStyle( color: Colors.white.withOpacity(0.9), fontSize: 14, ), ), Text( widget.sito.nome, style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ], ), ), ), ), ), bottom: TabBar( controller: _tabController, tabs: const [ Tab(text: 'Informazioni', icon: Icon(Icons.info_outline)), Tab(text: 'Allarmi', icon: Icon(Icons.notifications_active)), ], ), ), ]; }, body: TabBarView( controller: _tabController, children: [ // Tab Informazioni _buildInfoTab(dateFormat), // Tab Allarmi _buildAllarmiTab(), ], ), ), ); } Widget _buildInfoTab(DateFormat dateFormat) { return SingleChildScrollView( padding: const EdgeInsets.all(AppSizes.paddingL), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Statistiche rapide Row( children: [ Expanded( child: _buildStatCard( 'Allarmi Totali', _allarmi.length.toString(), Icons.notifications, AppColors.primary, ), ), const SizedBox(width: AppSizes.paddingM), Expanded( child: _buildStatCard( 'Critici', _allarmiCritici.toString(), Icons.warning, AppColors.critical, ), ), const SizedBox(width: AppSizes.paddingM), Expanded( child: _buildStatCard( 'Aperti', _allarmiAperti.toString(), Icons.pending, AppColors.warning, ), ), ], ), const SizedBox(height: 24), // Descrizione if (widget.sito.descrizione != null) ...[ const Text('Descrizione', style: AppTextStyles.h3), const SizedBox(height: 8), Text( widget.sito.descrizione!, style: AppTextStyles.bodyLarge, ), const SizedBox(height: 24), ], // Mappa if (widget.sito.hasCoordinates) ...[ const Text('Posizione', style: AppTextStyles.h3), const SizedBox(height: 12), _buildMapView(), const SizedBox(height: 24), ], // Dettagli tecnici const Text('Dettagli', style: AppTextStyles.h3), const SizedBox(height: 12), _buildInfoCard( icon: Icons.place, title: 'Località', value: widget.sito.localita, ), if (widget.sito.regione != null) ...[ const SizedBox(height: 8), _buildInfoCard( icon: Icons.map, title: 'Regione', value: widget.sito.regione!, ), ], if (widget.sito.codiceIdentificativo != null) ...[ const SizedBox(height: 8), _buildInfoCard( icon: Icons.qr_code, title: 'Codice Identificativo', value: widget.sito.codiceIdentificativo!, ), ], if (widget.sito.hasCoordinates) ...[ const SizedBox(height: 8), _buildInfoCard( icon: Icons.my_location, title: 'Coordinate', value: '${widget.sito.latitudine!.toStringAsFixed(6)}, ${widget.sito.longitudine!.toStringAsFixed(6)}', ), ], if (widget.sito.altitudine != null) ...[ const SizedBox(height: 8), _buildInfoCard( icon: Icons.height, title: 'Altitudine', value: '${widget.sito.altitudine!.toStringAsFixed(0)} m s.l.m.', ), ], const SizedBox(height: 8), _buildInfoCard( icon: Icons.calendar_today, title: 'Data creazione', value: dateFormat.format(widget.sito.createdAt), ), ], ), ); } Widget _buildAllarmiTab() { if (_isLoadingAllarmi) { return const Center(child: CircularProgressIndicator()); } if (_errorMessage != null) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, size: 64, color: AppColors.critical), const SizedBox(height: 16), Text(_errorMessage!), const SizedBox(height: 16), ElevatedButton.icon( onPressed: _loadAllarmi, icon: const Icon(Icons.refresh), label: const Text('Riprova'), ), ], ), ); } if (_allarmi.isEmpty) { return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.check_circle_outline, size: 64, color: AppColors.success), SizedBox(height: 16), Text('Nessun allarme registrato', style: AppTextStyles.h3), SizedBox(height: 8), Text( 'Questo sito non ha allarmi nello storico', style: AppTextStyles.bodyMedium, textAlign: TextAlign.center, ), ], ), ); } return RefreshIndicator( onRefresh: _loadAllarmi, child: ListView.builder( padding: const EdgeInsets.all(AppSizes.paddingM), itemCount: _allarmi.length, itemBuilder: (context, index) { return AllarmeCard(allarme: _allarmi[index]); }, ), ); } Widget _buildStatCard(String label, String value, IconData icon, Color color) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all(color: color.withOpacity(0.3)), ), child: Column( children: [ Icon(icon, color: color, size: 24), const SizedBox(height: 8), Text( value, style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: color, ), ), const SizedBox(height: 4), Text( label, style: TextStyle( fontSize: 11, color: color, ), textAlign: TextAlign.center, ), ], ), ); } Widget _buildInfoCard({ required IconData icon, required String title, required String value, }) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[300]!), ), child: Row( children: [ Icon(icon, color: _getTipoColor(), size: 20), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: AppTextStyles.bodySmall.copyWith( color: AppColors.textSecondary, ), ), const SizedBox(height: 2), Text( value, style: AppTextStyles.bodyMedium.copyWith( fontWeight: FontWeight.w600, ), ), ], ), ), ], ), ); } Widget _buildMapView() { if (!widget.sito.hasCoordinates) { return const SizedBox.shrink(); } final position = LatLng(widget.sito.latitudine!, widget.sito.longitudine!); return Container( height: 250, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[300]!), ), clipBehavior: Clip.hardEdge, child: GoogleMap( initialCameraPosition: CameraPosition( target: position, zoom: 14, ), markers: { Marker( markerId: MarkerId('sito_${widget.sito.id}'), position: position, infoWindow: InfoWindow( title: widget.sito.nome, snippet: widget.sito.tipoReadable, ), icon: BitmapDescriptor.defaultMarkerWithHue( _getTipoColor() == Colors.blue ? BitmapDescriptor.hueBlue : _getTipoColor() == Colors.green ? BitmapDescriptor.hueGreen : _getTipoColor() == Colors.orange ? BitmapDescriptor.hueOrange : BitmapDescriptor.hueRed, ), ), }, myLocationButtonEnabled: true, zoomControlsEnabled: true, mapToolbarEnabled: false, onMapCreated: (controller) { _mapController = controller; }, ), ); } }