import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../core/constants/app_constants.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/glass_container.dart'; import '../../core/widgets/weapon_type_icon.dart'; import '../../data/models/weapon.dart'; import '../../data/repositories/session_repository.dart'; import 'weapon_detail_screen.dart'; class WeaponListScreen extends StatefulWidget { final int refreshTick; const WeaponListScreen({super.key, this.refreshTick = 0}); @override State createState() => _WeaponListScreenState(); } class _WeaponListScreenState extends State { List _weapons = []; bool _isLoading = true; @override void initState() { super.initState(); _loadWeapons(); } @override void didUpdateWidget(WeaponListScreen oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.refreshTick != widget.refreshTick) { _loadWeapons(); } } Future _loadWeapons() async { final repository = context.read(); final weapons = await repository.getWeapons(); if (mounted) { setState(() { _weapons = weapons; _isLoading = false; }); } } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( extendBody: true, appBar: AppBar( title: const Text('Mon Armurerie'), actions: [ IconButton( icon: const Icon(Icons.add_circle_outline), tooltip: 'Ajouter une arme', onPressed: _showAddWeaponDialog, ), const SizedBox(width: 8), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : _weapons.isEmpty ? _buildEmptyState(isDark) : _buildWeaponList(isDark), ); } Widget _buildEmptyState(bool isDark) { return Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ GlassContainer( borderRadius: 30, padding: const EdgeInsets.all(28), child: Icon( Icons.shield_outlined, size: 64, color: isDark ? AppTheme.darkTextMuted : AppTheme.lightTextMuted, ), ), const SizedBox(height: 24), Text( 'Aucune arme enregistrée', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w800, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), const SizedBox(height: 8), Text( 'Ajoutez vos armes pour suivre vos tirs, chargeurs et entretiens.', textAlign: TextAlign.center, style: TextStyle( fontSize: 13, color: isDark ? AppTheme.darkTextSecondary : AppTheme.lightTextSecondary, ), ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: _showAddWeaponDialog, icon: const Icon(Icons.add), label: const Text('Ajouter ma première arme'), ), ], ), ), ); } Widget _buildWeaponList(bool isDark) { return ListView.builder( padding: const EdgeInsets.fromLTRB( AppConstants.defaultPadding, 12, AppConstants.defaultPadding, 100, // Espace pour le floating dock ), itemCount: _weapons.length, itemBuilder: (context, index) { final weapon = _weapons[index]; final accessories = _accessoryChips(weapon, isDark); final primaryColor = Theme.of(context).colorScheme.primary; return GlassContainer( borderRadius: 18, blur: 14, glowColor: primaryColor, borderColor: isDark ? primaryColor.withValues(alpha: 0.18) : primaryColor.withValues(alpha: 0.12), margin: const EdgeInsets.only(bottom: 14), padding: const EdgeInsets.all(16), onTap: () async { await Navigator.push( context, MaterialPageRoute( builder: (_) => WeaponDetailScreen(weapon: weapon), ), ); _loadWeapons(); }, onLongPress: () => _confirmDelete(weapon), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( gradient: LinearGradient( colors: [ primaryColor.withValues( alpha: isDark ? 0.25 : 0.15, ), primaryColor.withValues( alpha: 0.05, ), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(14), border: Border.all( color: primaryColor.withValues( alpha: isDark ? 0.35 : 0.2, ), ), ), child: WeaponTypeIcon( type: weapon.type, color: primaryColor, size: 28, ), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( weapon.displayName, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), const SizedBox(height: 4), Row( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 7, vertical: 2, ), decoration: BoxDecoration( color: (isDark ? Colors.white : Colors.black) .withValues(alpha: 0.08), borderRadius: BorderRadius.circular(6), border: Border.all( color: isDark ? AppTheme.darkBorder : AppTheme.lightBorder, ), ), child: Text( weapon.caliber, style: TextStyle( fontSize: 11, fontWeight: FontWeight.w800, color: primaryColor, ), ), ), const SizedBox(width: 8), Text( weapon.type.displayName, style: TextStyle( fontSize: 12, color: isDark ? AppTheme.darkTextSecondary : AppTheme.lightTextSecondary, ), ), ], ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '${weapon.magazineCount} chargeur${weapon.magazineCount > 1 ? 's' : ''}', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w700, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), const SizedBox(height: 2), Text( '${weapon.magazineCapacity} coups/ch.', style: TextStyle( fontSize: 11, color: isDark ? AppTheme.darkTextMuted : AppTheme.lightTextMuted, ), ), ], ), ], ), if (accessories.isNotEmpty) ...[ const SizedBox(height: 12), Wrap( spacing: 6, runSpacing: 6, children: accessories, ), ], ], ), ); }, ); } List _accessoryChips(Weapon weapon, bool isDark) { final items = <(IconData, String)>[]; if (weapon.optic != null && weapon.optic!.isNotEmpty) { items.add((Icons.center_focus_strong, weapon.optic!)); } if (weapon.silencer != null && weapon.silencer!.isNotEmpty) { items.add((Icons.volume_off, weapon.silencer!)); } if (weapon.trigger != null && weapon.trigger!.isNotEmpty) { items.add((Icons.touch_app, weapon.trigger!)); } return items.map((item) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: (isDark ? Colors.white : Colors.black).withValues(alpha: 0.05), borderRadius: BorderRadius.circular(8), border: Border.all( color: isDark ? AppTheme.darkBorder : AppTheme.lightBorder, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( item.$1, size: 13, color: isDark ? AppTheme.darkTextSecondary : AppTheme.lightTextSecondary, ), const SizedBox(width: 5), Text( item.$2, style: TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: isDark ? AppTheme.darkTextSecondary : AppTheme.lightTextSecondary, ), ), ], ), ); }).toList(); } void _showAddWeaponDialog() async { final repository = context.read(); final nameController = TextEditingController(); final caliberController = TextEditingController(); final magCountController = TextEditingController(text: '2'); final magCapController = TextEditingController(text: '15'); WeaponType selectedType = WeaponType.handgun; final result = await showDialog( context: context, builder: (dialogCtx) => StatefulBuilder( builder: (context, setState) => AlertDialog( title: const Text('Ajouter une arme'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: nameController, decoration: const InputDecoration( labelText: 'Nom de l\'arme', hintText: 'ex: Glock 17 Gen 5', ), ), const SizedBox(height: 12), DropdownButtonFormField( initialValue: selectedType, decoration: const InputDecoration(labelText: 'Type'), items: WeaponType.values .map( (t) => DropdownMenuItem( value: t, child: Row( children: [ WeaponTypeIcon(type: t, size: 20), const SizedBox(width: 10), Text(t.displayName), ], ), ), ) .toList(), onChanged: (v) => setState(() => selectedType = v!), ), const SizedBox(height: 12), TextField( controller: caliberController, decoration: const InputDecoration( labelText: 'Calibre', hintText: 'ex: 9x19mm, .22 LR, .223 Rem', ), ), const SizedBox(height: 12), Row( children: [ Expanded( child: TextField( controller: magCountController, decoration: const InputDecoration(labelText: 'Chargeurs'), keyboardType: TextInputType.number, ), ), const SizedBox(width: 12), Expanded( child: TextField( controller: magCapController, decoration: const InputDecoration(labelText: 'Capacité'), keyboardType: TextInputType.number, ), ), ], ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(dialogCtx, false), child: const Text('Annuler'), ), ElevatedButton( onPressed: () => Navigator.pop(dialogCtx, true), child: const Text('Ajouter'), ), ], ), ), ); if (result == true && nameController.text.isNotEmpty) { await repository.addWeapon( name: nameController.text, type: selectedType, caliber: caliberController.text, magazineCount: int.tryParse(magCountController.text) ?? 1, magazineCapacity: int.tryParse(magCapController.text) ?? 10, ); if (!mounted) return; _loadWeapons(); } } void _confirmDelete(Weapon weapon) async { final repository = context.read(); final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Supprimer l\'arme'), content: Text('Voulez-vous supprimer ${weapon.name} de votre armurerie ?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Annuler'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom( backgroundColor: AppTheme.errorColor, foregroundColor: Colors.white, ), child: const Text('Supprimer'), ), ], ), ); if (confirmed == true) { await repository.deleteWeapon(weapon.id); if (!mounted) return; _loadWeapons(); } } }