diff --git a/lib/data/database/database_helper.dart b/lib/data/database/database_helper.dart index f558a84e..5f285ec0 100644 --- a/lib/data/database/database_helper.dart +++ b/lib/data/database/database_helper.dart @@ -10,6 +10,12 @@ import '../../core/constants/app_constants.dart'; class DatabaseHelper { static DatabaseHelper? _instance; static Database? _database; + // On met en cache le Future d'initialisation (et non la Database résolue) + // pour éviter qu'un démarrage concurrent (les 4 onglets de l'IndexedStack + // interrogent la base en même temps) ne lance plusieurs _initDatabase() en + // parallèle. Sur une base fraîche, cela dédoublait onCreate et rendait la + // toute première écriture peu fiable. + static Future? _initFuture; DatabaseHelper._internal(); @@ -19,7 +25,9 @@ class DatabaseHelper { } Future get database async { - _database ??= await _initDatabase(); + if (_database != null) return _database!; + _initFuture ??= _initDatabase(); + _database = await _initFuture!; return _database!; } @@ -552,5 +560,6 @@ class DatabaseHelper { final db = await database; await db.close(); _database = null; + _initFuture = null; } } \ No newline at end of file diff --git a/lib/features/garage/weapon_detail_screen.dart b/lib/features/garage/weapon_detail_screen.dart index 5d042915..bfc42430 100644 --- a/lib/features/garage/weapon_detail_screen.dart +++ b/lib/features/garage/weapon_detail_screen.dart @@ -235,6 +235,33 @@ class _WeaponDetailScreenState extends State { } } + // Recentre le champ qui prend le focus au milieu de la vue restante une fois + // le clavier ouvert. Sans cela, l'AlertDialog se rétrécit et le champ ciblé + // (ex: Modérateur) se retrouve caché sous le clavier. + Widget _autoScrollOnFocus(Widget child) { + return Builder( + builder: (context) => Focus( + canRequestFocus: false, + skipTraversal: true, + onFocusChange: (hasFocus) { + if (!hasFocus) return; + // On attend que le clavier ait fini de redimensionner la vue. + Future.delayed(const Duration(milliseconds: 300), () { + if (context.mounted) { + Scrollable.ensureVisible( + context, + alignment: 0.5, + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + ); + } + }); + }, + child: child, + ), + ); + } + void _showEditWeaponDialog(BuildContext context) async { final nameController = TextEditingController(text: _weapon.name); final caliberController = TextEditingController(text: _weapon.caliber); @@ -256,41 +283,41 @@ class _WeaponDetailScreenState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - TextField( + _autoScrollOnFocus(TextField( controller: nameController, decoration: const InputDecoration(labelText: 'Modèle', hintText: 'ex: Glock 17'), - ), - TextField( + )), + _autoScrollOnFocus(TextField( controller: customNameController, decoration: const InputDecoration(labelText: 'Surnom / Custom Name', hintText: 'ex: Mon Glock de Compète'), - ), + )), DropdownButtonFormField( value: selectedType, decoration: const InputDecoration(labelText: 'Type'), items: WeaponType.values.map((t) => DropdownMenuItem(value: t, child: Text(t.displayName))).toList(), onChanged: (v) => setState(() => selectedType = v!), ), - TextField( + _autoScrollOnFocus(TextField( controller: caliberController, decoration: const InputDecoration(labelText: 'Calibre'), - ), + )), const SizedBox(height: 16), const Text('Équipement & Options', style: TextStyle(fontWeight: FontWeight.bold)), - TextField( + _autoScrollOnFocus(TextField( controller: opticController, decoration: const InputDecoration(labelText: 'Optique / Lunette', hintText: 'ex: Holosun 507C'), - ), - TextField( + )), + _autoScrollOnFocus(TextField( controller: silencerController, decoration: const InputDecoration(labelText: 'Modérateur / Silencieux'), - ), - TextField( + )), + _autoScrollOnFocus(TextField( controller: triggerController, decoration: const InputDecoration(labelText: 'Détente / Trigger'), - ), + )), const SizedBox(height: 16), const Text('Logistique', style: TextStyle(fontWeight: FontWeight.bold)), - Row( + _autoScrollOnFocus(Row( children: [ Expanded( child: TextField( @@ -308,12 +335,12 @@ class _WeaponDetailScreenState extends State { ), ), ], - ), - TextField( + )), + _autoScrollOnFocus(TextField( controller: notesController, decoration: const InputDecoration(labelText: 'Notes'), maxLines: 2, - ), + )), ], ), ),