perf: Implémentation du lazy loading pour le calendrier
Cette mise à jour refactorise en profondeur le chargement des événements sur la page Calendrier pour améliorer drastiquement les performances et la réactivité de l'application, en particulier pour les utilisateurs avec un grand nombre d'événements. Le système de chargement initial de tous les événements est remplacé par un mécanisme de lazy loading qui ne récupère que les données du mois affiché.
**Changements majeurs :**
- **Lazy Loading Côté Client (`EventProvider`) :**
- Une nouvelle méthode `loadMonthEvents` a été introduite pour charger uniquement les événements d'un mois spécifique (`year`, `month`).
- Un cache par mois (`_eventsByMonth`) a été mis en place pour éviter les rechargements inutiles lors de la navigation entre des mois déjà consultés.
- Ajout d'une fonction `preloadAdjacentMonths` qui charge en arrière-plan et silencieusement les mois précédent et suivant, assurant une navigation fluide dans le calendrier.
- **Nouveau Endpoint Backend (`getEventsByMonth`) :**
- Création d'un nouvel endpoint Cloud Function `getEventsByMonth` optimisé pour ne requêter que les événements dans une plage de dates (début et fin du mois).
- La fonction récupère les utilisateurs associés de manière optimisée en parallélisant les requêtes Firestore (Promise.all).
- La limite du nombre d'IDs par requête 'in' a été augmentée de 10 à 30 pour réduire le nombre d'appels à la base de données.
- **Intégration au Calendrier (`CalendarPage`) :**
- La page charge désormais les événements pour le mois courant au démarrage via `_loadCurrentMonthEvents`.
- Lorsqu'un utilisateur change de mois (`onPageChanged`), la page déclenche le chargement des données pour le nouveau mois, avec un préchargement des mois adjacents pour anticiper la navigation.
- Le chargement initial de tous les événements (`_loadEventsAsync`) a été déprécié.
- **Correction de la Séquence de Démarrage (`main.dart`) :**
- L'appel à `_autoLogin` est maintenant enveloppé dans `WidgetsBinding.instance.addPostFrameCallback`. Cela garantit que la navigation ne se produit qu'après le premier rendu de l'interface, évitant ainsi des erreurs potentielles de build/navigation concurrentes et fiabilisant le chargement initial des données utilisateur.
This commit is contained in:
@@ -36,11 +36,51 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
initializeDateFormatting('fr_FR', null);
|
||||
// Charger les événements de manière asynchrone sans bloquer l'UI
|
||||
_loadEventsAsync();
|
||||
// Charger les événements du mois courant après le premier build
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_loadCurrentMonthEvents();
|
||||
});
|
||||
}
|
||||
|
||||
/// Charge les événements du mois courant avec lazy loading
|
||||
Future<void> _loadCurrentMonthEvents() async {
|
||||
PerformanceMonitor.start('CalendarPage.loadCurrentMonthEvents');
|
||||
|
||||
final localAuthProvider = Provider.of<LocalUserProvider>(context, listen: false);
|
||||
final eventProvider = Provider.of<EventProvider>(context, listen: false);
|
||||
final userId = localAuthProvider.uid;
|
||||
final canViewAllEvents = localAuthProvider.hasPermission('view_all_events');
|
||||
|
||||
if (userId != null) {
|
||||
print('[CalendarPage] Loading events for ${_focusedDay.year}-${_focusedDay.month}');
|
||||
|
||||
await eventProvider.loadMonthEvents(
|
||||
userId,
|
||||
_focusedDay.year,
|
||||
_focusedDay.month,
|
||||
canViewAllEvents: canViewAllEvents,
|
||||
);
|
||||
|
||||
// Précharger les mois adjacents en arrière-plan
|
||||
eventProvider.preloadAdjacentMonths(
|
||||
userId,
|
||||
_focusedDay.year,
|
||||
_focusedDay.month,
|
||||
canViewAllEvents: canViewAllEvents,
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
PerformanceMonitor.start('CalendarPage.selectDefaultEvent');
|
||||
_selectDefaultEvent();
|
||||
PerformanceMonitor.end('CalendarPage.selectDefaultEvent');
|
||||
}
|
||||
}
|
||||
|
||||
PerformanceMonitor.end('CalendarPage.loadCurrentMonthEvents');
|
||||
}
|
||||
|
||||
/// Charge les événements de manière asynchrone et sélectionne l'événement approprié
|
||||
/// DEPRECATED: Utiliser _loadCurrentMonthEvents à la place
|
||||
Future<void> _loadEventsAsync() async {
|
||||
PerformanceMonitor.start('CalendarPage.loadEventsAsync');
|
||||
await _loadEvents();
|
||||
@@ -157,6 +197,12 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
// Appliquer le filtre utilisateur si actif
|
||||
final filteredEvents = _getFilteredEvents(eventProvider.events);
|
||||
|
||||
// Debug logs
|
||||
print('[CalendarPage.build] Total events: ${eventProvider.events.length}, Filtered: ${filteredEvents.length}');
|
||||
if (eventProvider.events.isNotEmpty) {
|
||||
print('[CalendarPage.build] First event: ${eventProvider.events.first.name} at ${eventProvider.events.first.startDateTime}');
|
||||
}
|
||||
|
||||
if (eventProvider.isLoading) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
@@ -659,9 +705,19 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
});
|
||||
},
|
||||
onPageChanged: (focusedDay) {
|
||||
// Détecter si on a changé de mois
|
||||
final monthChanged = focusedDay.year != _focusedDay.year ||
|
||||
focusedDay.month != _focusedDay.month;
|
||||
|
||||
setState(() {
|
||||
_focusedDay = focusedDay;
|
||||
});
|
||||
|
||||
// Charger les événements du nouveau mois si nécessaire
|
||||
if (monthChanged) {
|
||||
print('[CalendarPage] Month changed to ${focusedDay.year}-${focusedDay.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
}
|
||||
},
|
||||
onEventSelected: (event) {
|
||||
setState(() {
|
||||
|
||||
Reference in New Issue
Block a user