Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f80d9318b |
@@ -1,6 +1,10 @@
|
|||||||
# Changelog - EM2RP
|
# Changelog - EM2RP
|
||||||
|
|
||||||
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
|
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
|
||||||
|
|
||||||
|
## 24/03/2026
|
||||||
|
Fix BUG : Problème de cache avec les équipements non affichés dans le dialog de sélection d'équipement. Amélioration de la gestion du cache pour éviter les problèmes d'affichage.
|
||||||
|
|
||||||
## 12/03/2026bis
|
## 12/03/2026bis
|
||||||
Fix BUG : Ajout equipement à un evenement existant, boutons de modification de statut d'un evenement ne fonctionnaient pas. Refonte legere de la page calendrier.
|
Fix BUG : Ajout equipement à un evenement existant, boutons de modification de statut d'un evenement ne fonctionnaient pas. Refonte legere de la page calendrier.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/// Configuration de la version de l'application
|
/// Configuration de la version de l'application
|
||||||
class AppVersion {
|
class AppVersion {
|
||||||
static const String version = '1.1.18';
|
static const String version = '1.1.19';
|
||||||
|
|
||||||
/// Retourne la version complète de l'application
|
/// Retourne la version complète de l'application
|
||||||
static String get fullVersion => 'v$version';
|
static String get fullVersion => 'v$version';
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
child: ListView(
|
child: ListView(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
// Nom
|
// Nom
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
@@ -257,7 +256,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.scale),
|
prefixIcon: Icon(Icons.scale),
|
||||||
),
|
),
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
keyboardType:
|
||||||
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value != null && value.isNotEmpty) {
|
if (value != null && value.isNotEmpty) {
|
||||||
if (double.tryParse(value) == null) {
|
if (double.tryParse(value) == null) {
|
||||||
@@ -279,7 +279,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
labelText: 'Longueur (cm)',
|
labelText: 'Longueur (cm)',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType:
|
||||||
|
TextInputType.numberWithOptions(decimal: true),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value != null && value.isNotEmpty) {
|
if (value != null && value.isNotEmpty) {
|
||||||
if (double.tryParse(value) == null) {
|
if (double.tryParse(value) == null) {
|
||||||
@@ -298,7 +299,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
labelText: 'Largeur (cm)',
|
labelText: 'Largeur (cm)',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType:
|
||||||
|
TextInputType.numberWithOptions(decimal: true),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value != null && value.isNotEmpty) {
|
if (value != null && value.isNotEmpty) {
|
||||||
if (double.tryParse(value) == null) {
|
if (double.tryParse(value) == null) {
|
||||||
@@ -317,7 +319,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
labelText: 'Hauteur (cm)',
|
labelText: 'Hauteur (cm)',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType:
|
||||||
|
TextInputType.numberWithOptions(decimal: true),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value != null && value.isNotEmpty) {
|
if (value != null && value.isNotEmpty) {
|
||||||
if (double.tryParse(value) == null) {
|
if (double.tryParse(value) == null) {
|
||||||
@@ -452,6 +455,11 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
Future<void> _selectEquipment() async {
|
Future<void> _selectEquipment() async {
|
||||||
final equipmentProvider = context.read<EquipmentProvider>();
|
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(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => _EquipmentSelectorDialog(
|
builder: (context) => _EquipmentSelectorDialog(
|
||||||
@@ -460,6 +468,7 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,7 +544,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
equipmentId: equipmentId,
|
equipmentId: equipmentId,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} 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
|
// 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) {
|
for (final equipmentId in addedEquipment) {
|
||||||
try {
|
try {
|
||||||
await provider.addEquipmentToContainer(
|
await provider.addEquipmentToContainer(
|
||||||
@@ -581,12 +592,14 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
equipmentId: equipmentId,
|
equipmentId: equipmentId,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} 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
|
// 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) {
|
for (final equipmentId in removedEquipment) {
|
||||||
try {
|
try {
|
||||||
await provider.removeEquipmentFromContainer(
|
await provider.removeEquipmentFromContainer(
|
||||||
@@ -594,7 +607,8 @@ class _ContainerFormPageState extends State<ContainerFormPage> {
|
|||||||
equipmentId: equipmentId,
|
equipmentId: equipmentId,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} 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
|
@override
|
||||||
State<_EquipmentSelectorDialog> createState() => _EquipmentSelectorDialogState();
|
State<_EquipmentSelectorDialog> createState() =>
|
||||||
|
_EquipmentSelectorDialogState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
|
class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
|
||||||
@@ -638,12 +653,14 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
|
|||||||
EquipmentCategory? _filterCategory;
|
EquipmentCategory? _filterCategory;
|
||||||
String _searchQuery = '';
|
String _searchQuery = '';
|
||||||
late Set<String> _tempSelectedIds;
|
late Set<String> _tempSelectedIds;
|
||||||
|
late final Future<void> _loadingFuture;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// Créer une copie temporaire des IDs sélectionnés
|
// Créer une copie temporaire des IDs sélectionnés
|
||||||
_tempSelectedIds = Set<String>.from(widget.selectedIds);
|
_tempSelectedIds = Set<String>.from(widget.selectedIds);
|
||||||
|
_loadingFuture = widget.equipmentProvider.loadEquipments();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -729,7 +746,8 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
|
|||||||
},
|
},
|
||||||
selectedColor: AppColors.rouge,
|
selectedColor: AppColors.rouge,
|
||||||
labelStyle: TextStyle(
|
labelStyle: TextStyle(
|
||||||
color: _filterCategory == null ? Colors.white : Colors.black,
|
color:
|
||||||
|
_filterCategory == null ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -746,7 +764,9 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
|
|||||||
},
|
},
|
||||||
selectedColor: AppColors.rouge,
|
selectedColor: AppColors.rouge,
|
||||||
labelStyle: TextStyle(
|
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
|
// Liste des équipements
|
||||||
Expanded(
|
Expanded(
|
||||||
child: StreamBuilder<List<EquipmentModel>>(
|
child: FutureBuilder<void>(
|
||||||
stream: widget.equipmentProvider.equipmentStream,
|
future: _loadingFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
@@ -789,11 +809,15 @@ class _EquipmentSelectorDialogState extends State<_EquipmentSelectorDialog> {
|
|||||||
return Center(child: Text('Erreur: ${snapshot.error}'));
|
return Center(child: Text('Erreur: ${snapshot.error}'));
|
||||||
}
|
}
|
||||||
|
|
||||||
var equipment = snapshot.data ?? [];
|
var equipment = List<EquipmentModel>.from(
|
||||||
|
widget.equipmentProvider.allEquipment,
|
||||||
|
);
|
||||||
|
|
||||||
// Filtrer par catégorie
|
// Filtrer par catégorie
|
||||||
if (_filterCategory != null) {
|
if (_filterCategory != null) {
|
||||||
equipment = equipment.where((e) => e.category == _filterCategory).toList();
|
equipment = equipment
|
||||||
|
.where((e) => e.category == _filterCategory)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filtrer par recherche
|
// Filtrer par recherche
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
|||||||
|
bool shouldAutoLoadNextPage({
|
||||||
|
required bool hasMoreData,
|
||||||
|
required bool isLoadingMore,
|
||||||
|
required bool hasClients,
|
||||||
|
required double maxScrollExtent,
|
||||||
|
}) {
|
||||||
|
if (!hasMoreData || isLoadingMore) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the list cannot scroll yet, preload the next page to avoid a truncated view.
|
||||||
|
return !hasClients || maxScrollExtent <= 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import 'package:em2rp/views/widgets/event/equipment_selection_pagination.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('shouldAutoLoadNextPage', () {
|
||||||
|
test('returns false when there is no more data', () {
|
||||||
|
final result = shouldAutoLoadNextPage(
|
||||||
|
hasMoreData: false,
|
||||||
|
isLoadingMore: false,
|
||||||
|
hasClients: true,
|
||||||
|
maxScrollExtent: 100,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns false while a page is already loading', () {
|
||||||
|
final result = shouldAutoLoadNextPage(
|
||||||
|
hasMoreData: true,
|
||||||
|
isLoadingMore: true,
|
||||||
|
hasClients: true,
|
||||||
|
maxScrollExtent: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns true when list has no scroll client yet', () {
|
||||||
|
final result = shouldAutoLoadNextPage(
|
||||||
|
hasMoreData: true,
|
||||||
|
isLoadingMore: false,
|
||||||
|
hasClients: false,
|
||||||
|
maxScrollExtent: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns true when list is not scrollable yet', () {
|
||||||
|
final result = shouldAutoLoadNextPage(
|
||||||
|
hasMoreData: true,
|
||||||
|
isLoadingMore: false,
|
||||||
|
hasClients: true,
|
||||||
|
maxScrollExtent: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns false when list is scrollable', () {
|
||||||
|
final result = shouldAutoLoadNextPage(
|
||||||
|
hasMoreData: true,
|
||||||
|
isLoadingMore: false,
|
||||||
|
hasClients: true,
|
||||||
|
maxScrollExtent: 250,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result, isFalse);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "1.1.18",
|
"version": "1.1.19",
|
||||||
"updateUrl": "https://app.em2events.fr",
|
"updateUrl": "https://app.em2events.fr",
|
||||||
"forceUpdate": true,
|
"forceUpdate": true,
|
||||||
"releaseNotes": "Fix BUG : Ajout equipement à un evenement existant, boutons de modification de statut d'un evenement ne fonctionnaient pas. Refonte legere de la page calendrier.",
|
"releaseNotes": "Fix BUG : Problème de cache avec les équipements non affichés dans le dialog de sélection d'équipement. Amélioration de la gestion du cache pour éviter les problèmes d'affichage.",
|
||||||
"timestamp": "2026-03-12T20:11:54.548Z"
|
"timestamp": "2026-03-24T11:14:01.828Z"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user