From 96cc487b55f0302f083d8478a6b862912b365537 Mon Sep 17 00:00:00 2001 From: qlionbleusam Date: Sat, 29 Aug 2026 08:48:41 +0200 Subject: [PATCH 1/2] feat(session): add armory shortcut and 50-shot preset --- .../session/session_setup_screen.dart | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/features/session/session_setup_screen.dart b/lib/features/session/session_setup_screen.dart index 68657c48..6e55fb62 100644 --- a/lib/features/session/session_setup_screen.dart +++ b/lib/features/session/session_setup_screen.dart @@ -28,7 +28,7 @@ class _SessionSetupScreenState extends State { DateTime _selectedDate = DateTime.now(); static const List _presetDistances = [10, 15, 25, 50, 100, 200]; - static const List _presetShots = [3, 5, 10, 15, 20, 30]; + static const List _presetShots = [3, 5, 10, 15, 20, 30, 50]; @override void initState() { @@ -53,6 +53,35 @@ class _SessionSetupScreenState extends State { } } + Future _openArmory() async { + final knownIds = _availableWeapons.map((w) => w.id).toSet(); + + await Navigator.push( + context, + MaterialPageRoute(builder: (_) => const WeaponListScreen()), + ); + if (!mounted) return; + + await _loadWeapons(); + if (!mounted) return; + + // Selectionne automatiquement l'arme qui vient d'etre ajoutee. + Weapon? added; + for (final weapon in _availableWeapons) { + if (!knownIds.contains(weapon.id)) { + added = weapon; + break; + } + } + if (added != null) { + final newWeapon = added; + setState(() { + _selectedWeapon = newWeapon; + _updateSettingsForWeapon(newWeapon); + }); + } + } + void _updateSettingsForWeapon(Weapon weapon) { _shotsPerTarget = weapon.magazineCapacity > 0 ? weapon.magazineCapacity : 5; _distance = (weapon.type == WeaponType.handgun) ? 25 : 50; @@ -177,12 +206,7 @@ class _SessionSetupScreenState extends State { ), const SizedBox(height: 20), ElevatedButton.icon( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (_) => const WeaponListScreen()), - ).then((_) => _loadWeapons()); - }, + onPressed: _openArmory, icon: const Icon(Icons.shield), label: const Text('Aller à l\'armurerie'), ), @@ -236,7 +260,21 @@ class _SessionSetupScreenState extends State { } }, ), - const SizedBox(height: 12), + const SizedBox(height: 4), + Align( + alignment: Alignment.centerLeft, + child: TextButton.icon( + onPressed: _openArmory, + icon: const Icon(Icons.add_circle_outline, size: 18), + label: const Text('Ajouter une nouvelle arme'), + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + visualDensity: VisualDensity.compact, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + ), + ), + const SizedBox(height: 8), InkWell( onTap: _pickDate, borderRadius: BorderRadius.circular(12), From 6dc525c0db20c7ce87f48f0cb2569c091f75abb0 Mon Sep 17 00:00:00 2001 From: qlionbleusam Date: Sat, 29 Aug 2026 09:11:20 +0200 Subject: [PATCH 2/2] fix(session): keep weapon selection valid when returning from the armory --- .../session/session_setup_screen.dart | 103 ++++++++++++------ 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/lib/features/session/session_setup_screen.dart b/lib/features/session/session_setup_screen.dart index 6e55fb62..0a22e62c 100644 --- a/lib/features/session/session_setup_screen.dart +++ b/lib/features/session/session_setup_screen.dart @@ -27,6 +27,12 @@ class _SessionSetupScreenState extends State { DateTime _selectedDate = DateTime.now(); + /// Valeur sentinelle de l'item "Ajouter une nouvelle arme" du menu deroulant. + static const String _addWeaponValue = '__add_weapon__'; + + final GlobalKey> _weaponFieldKey = + GlobalKey>(); + static const List _presetDistances = [10, 15, 25, 50, 100, 200]; static const List _presetShots = [3, 5, 10, 15, 20, 30, 50]; @@ -44,8 +50,21 @@ class _SessionSetupScreenState extends State { if (mounted) { setState(() { _availableWeapons = weapons; - if (_availableWeapons.isNotEmpty && _selectedWeapon == null) { - _selectedWeapon = _availableWeapons.first; + + // Les armes rechargees sont de nouvelles instances (Weapon n'a pas + // d'operator ==) et l'arme selectionnee a pu etre supprimee : on + // re-resout la selection par identifiant. + final previousId = _selectedWeapon?.id; + _selectedWeapon = null; + for (final weapon in weapons) { + if (weapon.id == previousId) { + _selectedWeapon = weapon; + break; + } + } + + if (_selectedWeapon == null && weapons.isNotEmpty) { + _selectedWeapon = weapons.first; _updateSettingsForWeapon(_selectedWeapon!); } _isLoadingWeapons = false; @@ -237,44 +256,64 @@ class _SessionSetupScreenState extends State { ], ), const SizedBox(height: 16), - DropdownButtonFormField( - initialValue: _selectedWeapon, + DropdownButtonFormField( + key: _weaponFieldKey, + initialValue: _selectedWeapon?.id, decoration: const InputDecoration( labelText: 'Arme utilisée', prefixIcon: Icon(Icons.shield_outlined), ), - items: _availableWeapons - .map( - (w) => DropdownMenuItem( - value: w, - child: Text('${w.displayName} (${w.caliber})'), - ), - ) - .toList(), + items: [ + ..._availableWeapons.map( + (w) => DropdownMenuItem( + value: w.id, + child: Text('${w.displayName} (${w.caliber})'), + ), + ), + DropdownMenuItem( + value: _addWeaponValue, + child: Row( + children: [ + Icon( + Icons.add_circle_outline, + size: 18, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 8), + Text( + 'Ajouter une nouvelle arme', + style: TextStyle( + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], + ), + ), + ], onChanged: (value) { - if (value != null) { - setState(() { - _selectedWeapon = value; - _updateSettingsForWeapon(value); - }); + if (value == null) return; + + if (value == _addWeaponValue) { + // L'item d'action n'est pas une arme : on restaure aussitot + // la selection precedente avant d'ouvrir l'armurerie. + _weaponFieldKey.currentState?.didChange(_selectedWeapon?.id); + _openArmory(); + return; + } + + for (final weapon in _availableWeapons) { + if (weapon.id == value) { + setState(() { + _selectedWeapon = weapon; + _updateSettingsForWeapon(weapon); + }); + break; + } } }, ), - const SizedBox(height: 4), - Align( - alignment: Alignment.centerLeft, - child: TextButton.icon( - onPressed: _openArmory, - icon: const Icon(Icons.add_circle_outline, size: 18), - label: const Text('Ajouter une nouvelle arme'), - style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - visualDensity: VisualDensity.compact, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - ), - ), - const SizedBox(height: 8), + const SizedBox(height: 12), InkWell( onTap: _pickDate, borderRadius: BorderRadius.circular(12),