feat: Mise à jour à la version 1.1.19 et amélioration du cache/pagination pour la sélection d'équipements

- Mise à jour de la version de l'application à `1.1.19` dans `app_version.dart` et `version.json`.
- Correction d'un bug de cache dans `EquipmentSelectionDialog` qui empêchait l'affichage de certains équipements lors de la sélection.
- Introduction d'une fonction utilitaire `shouldAutoLoadNextPage` et de tests unitaires associés pour fiabiliser le chargement automatique des données.
- Ajout d'une gestion de préchargement automatique dans `EquipmentSelectionDialog` lorsque la liste n'est pas assez longue pour activer le défilement (évite les vues tronquées).
- Amélioration de `ContainerFormPage` pour forcer le rechargement complet de la liste des équipements, évitant ainsi les conflits avec les états de pagination d'autres écrans.
- Optimisation du chargement des conflits de disponibilité et des quantités via un chargement par lots (batch).
- Nettoyage du code et amélioration de la lisibilité des fichiers `container_form_page.dart` et `equipment_selection_dialog.dart`.
This commit is contained in:
ElPoyo
2026-03-24 12:18:00 +01:00
parent ecf4a5cede
commit 3f80d9318b
7 changed files with 929 additions and 645 deletions

View File

@@ -100,7 +100,6 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
child: ListView(
padding: const EdgeInsets.all(24),
children: [
// Nom
TextFormField(
controller: _nameController,
@@ -257,7 +256,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.scale),
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
validator: (value) {
if (value != null && value.isNotEmpty) {
if (double.tryParse(value) == null) {
@@ -279,7 +279,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
labelText: 'Longueur (cm)',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.numberWithOptions(decimal: true),
keyboardType:
TextInputType.numberWithOptions(decimal: true),
validator: (value) {
if (value != null && value.isNotEmpty) {
if (double.tryParse(value) == null) {
@@ -298,7 +299,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
labelText: 'Largeur (cm)',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.numberWithOptions(decimal: true),
keyboardType:
TextInputType.numberWithOptions(decimal: true),
validator: (value) {
if (value != null && value.isNotEmpty) {
if (double.tryParse(value) == null) {
@@ -317,7 +319,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
labelText: 'Hauteur (cm)',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.numberWithOptions(decimal: true),
keyboardType:
TextInputType.numberWithOptions(decimal: true),
validator: (value) {
if (value != null && value.isNotEmpty) {
if (double.tryParse(value) == null) {
@@ -452,6 +455,11 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
Future<void> _selectEquipment() async {
final equipmentProvider = context.read<EquipmentProvider>();
// Toujours charger la liste complète pour éviter d'afficher uniquement
// la page paginée active d'un autre écran.
await equipmentProvider.loadEquipments();
if (!mounted) return;
await showDialog(
context: context,
builder: (context) => _EquipmentSelectorDialog(
@@ -460,6 +468,7 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
),
);
if (!mounted) return;
setState(() {});
}
@@ -535,7 +544,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
equipmentId: equipmentId,
);
} catch (e) {
DebugLog.error('Erreur lors de l\'ajout de l\'équipement $equipmentId', e);
DebugLog.error(
'Erreur lors de l\'ajout de l\'équipement $equipmentId', e);
}
}
@@ -573,7 +583,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
});
// Gérer les équipements ajoutés
final addedEquipment = _selectedEquipmentIds.difference(container.equipmentIds.toSet());
final addedEquipment =
_selectedEquipmentIds.difference(container.equipmentIds.toSet());
for (final equipmentId in addedEquipment) {
try {
await provider.addEquipmentToContainer(
@@ -581,12 +592,14 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
equipmentId: equipmentId,
);
} catch (e) {
DebugLog.error('Erreur lors de l\'ajout de l\'équipement $equipmentId', e);
DebugLog.error(
'Erreur lors de l\'ajout de l\'équipement $equipmentId', e);
}
}
// Gérer les équipements retirés
final removedEquipment = container.equipmentIds.toSet().difference(_selectedEquipmentIds);
final removedEquipment =
container.equipmentIds.toSet().difference(_selectedEquipmentIds);
for (final equipmentId in removedEquipment) {
try {
await provider.removeEquipmentFromContainer(
@@ -594,7 +607,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
equipmentId: equipmentId,
);
} catch (e) {
DebugLog.error('Erreur lors du retrait de l\'équipement $equipmentId', e);
DebugLog.error(
'Erreur lors du retrait de l\'équipement $equipmentId', e);
}
}
@@ -630,7 +644,8 @@ class _EquipmentSelectorDialog extends StatefulWidget {
});
@override
State<_EquipmentSelectorDialog> createState() => _EquipmentSelectorDialogState();
State<_EquipmentSelectorDialog> createState() =>
_EquipmentSelectorDialogState();
}
class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
@@ -638,12 +653,14 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
EquipmentCategory? _filterCategory;
String _searchQuery = '';
late Set<String> _tempSelectedIds;
late final Future<void> _loadingFuture;
@override
void initState() {
super.initState();
// Créer une copie temporaire des IDs sélectionnés
_tempSelectedIds = Set<String>.from(widget.selectedIds);
_loadingFuture = widget.equipmentProvider.loadEquipments();
}
@override
@@ -729,7 +746,8 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
},
selectedColor: AppColors.rouge,
labelStyle: TextStyle(
color: _filterCategory == null ? Colors.white : Colors.black,
color:
_filterCategory == null ? Colors.white : Colors.black,
),
),
const SizedBox(width: 8),
@@ -746,7 +764,9 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
},
selectedColor: AppColors.rouge,
labelStyle: TextStyle(
color: _filterCategory == category ? Colors.white : Colors.black,
color: _filterCategory == category
? Colors.white
: Colors.black,
),
),
);
@@ -778,8 +798,8 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
// Liste des équipements
Expanded(
child: StreamBuilder<List<EquipmentModel>>(
stream: widget.equipmentProvider.equipmentStream,
child: FutureBuilder<void>(
future: _loadingFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
@@ -789,11 +809,15 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
return Center(child: Text('Erreur: ${snapshot.error}'));
}
var equipment = snapshot.data ?? [];
var equipment = List<EquipmentModel>.from(
widget.equipmentProvider.allEquipment,
);
// Filtrer par catégorie
if (_filterCategory != null) {
equipment = equipment.where((e) => e.category == _filterCategory).toList();
equipment = equipment
.where((e) => e.category == _filterCategory)
.toList();
}
// Filtrer par recherche
@@ -801,8 +825,8 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
final query = _searchQuery.toLowerCase();
equipment = equipment.where((e) {
return e.id.toLowerCase().contains(query) ||
(e.brand?.toLowerCase().contains(query) ?? false) ||
(e.model?.toLowerCase().contains(query) ?? false);
(e.brand?.toLowerCase().contains(query) ?? false) ||
(e.model?.toLowerCase().contains(query) ?? false);
}).toList();
}
@@ -945,4 +969,4 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
return Icons.category;
}
}
}
}