Cette mise à jour majeure vise à améliorer significativement les performances de l'application, en particulier au démarrage, et à standardiser l'infrastructure backend. Les principaux changements incluent la migration de toutes les Cloud Functions vers une région européenne (`europe-west9`), l'optimisation du chargement des données, et l'introduction d'un moniteur de performance pour le débogage.
**Changements Backend (Cloud Functions) :**
- **Migration de la Région :**
- Toutes les Cloud Functions ont été déplacées de `us-central1` à `europe-west9` (Paris) pour réduire la latence pour les utilisateurs européens. Cela concerne les appels depuis le frontend (ex: `api_config.dart`, `email_service.dart`) et les définitions des fonctions elles-mêmes (`index.js`, etc.).
- **Standardisation des Fonctions :**
- La plupart des fonctions `onCall` (v1) ont été migrées vers le format `onRequest` (v2) avec une gestion d'authentification et de CORS unifiée, améliorant la robustesse et la cohérence.
- Les triggers Firestore (`onDocumentCreated`, `onDocumentUpdated`) et les tâches planifiées (`onSchedule`) ont été mis à jour pour spécifier explicitement la région `europe-west9`.
- **Mise à jour des Index Firestore :**
- Les index `firestore.indexes.json` ont été mis à jour pour supporter les nouvelles requêtes de l'application et optimiser les performances de filtrage.
**Améliorations des Performances Frontend :**
- **Chargement Asynchrone et Mis en Cache :**
- Le chargement des données utilisateur (`LocalUserProvider`) et des événements (`EventProvider`) a été optimisé pour utiliser un cache local à court terme (5 minutes pour l'utilisateur, 30 secondes pour les événements).
- Les données ne sont rechargées que si le cache a expiré ou si un rechargement est forcé, évitant des appels réseau redondants et accélérant la navigation.
- **Démarrage de l'Application Optimisé :**
- Le processus de connexion automatique (`main.dart`) a été revu. L'application navigue désormais immédiatement vers la page demandée sans attendre la fin du chargement des données utilisateur, qui s'effectue en arrière-plan.
- Un écran de chargement plus esthétique avec le logo de l'entreprise a été ajouté, remplaçant l'indicateur de chargement simple.
- **Chargement de la Page Calendrier :**
- Le chargement et la sélection de l'événement par défaut sur la page `CalendarPage` sont maintenant entièrement asynchrones, rendant l'affichage de la page quasi instantané.
**Nouveaux Outils et Améliorations UX :**
- **Moniteur de Performance :**
- Ajout d'un nouvel outil `PerformanceMonitor` (`lib/utils/performance_monitor.dart`) pour mesurer précisément le temps d'exécution des opérations critiques (appels API, parsing, etc.) en mode débogage. Il aide à identifier les goulots d'étranglement.
- **Amélioration du Formulaire de Connexion :**
- Les champs "Email" et "Mot de passe" sur la page de connexion (`LoginPage`) supportent désormais l'autocomplétion du navigateur (`AutofillGroup`).
- Appuyer sur "Entrée" dans l'un des champs déclenche désormais la connexion, améliorant l'ergonomie.
**Mise à jour de la version :**
- La version de l'application a été incrémentée à `1.0.9`.
130 lines
3.5 KiB
Dart
130 lines
3.5 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
|
|
/// Service de monitoring des performances de l'application
|
|
/// Permet de mesurer les temps de chargement et d'identifier les goulots d'étranglement
|
|
class PerformanceMonitor {
|
|
static final Map<String, DateTime> _timings = {};
|
|
static final Map<String, Duration> _results = {};
|
|
static bool _enabled = kDebugMode; // Actif uniquement en mode debug par défaut
|
|
|
|
/// Active ou désactive le monitoring
|
|
static void setEnabled(bool enabled) {
|
|
_enabled = enabled;
|
|
}
|
|
|
|
/// Démarre le chronomètre pour une opération
|
|
static void start(String key) {
|
|
if (!_enabled) return;
|
|
_timings[key] = DateTime.now();
|
|
if (kDebugMode) {
|
|
print('[PerformanceMonitor] START: $key');
|
|
}
|
|
}
|
|
|
|
/// Arrête le chronomètre et affiche le résultat
|
|
static void end(String key) {
|
|
if (!_enabled) return;
|
|
|
|
if (_timings.containsKey(key)) {
|
|
final duration = DateTime.now().difference(_timings[key]!);
|
|
_results[key] = duration;
|
|
_timings.remove(key);
|
|
|
|
if (kDebugMode) {
|
|
final color = _getColorForDuration(duration);
|
|
print('[PerformanceMonitor] $color END: $key - ${duration.inMilliseconds}ms');
|
|
}
|
|
} else {
|
|
if (kDebugMode) {
|
|
print('[PerformanceMonitor] ⚠️ No start time found for: $key');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Marque un point dans le temps (pour mesurer des étapes)
|
|
static void mark(String key) {
|
|
if (!_enabled) return;
|
|
|
|
if (kDebugMode) {
|
|
print('[PerformanceMonitor] 📍 MARK: $key');
|
|
}
|
|
}
|
|
|
|
/// Récupère les résultats de toutes les mesures
|
|
static Map<String, Duration> getResults() {
|
|
return Map.unmodifiable(_results);
|
|
}
|
|
|
|
/// Affiche un résumé des performances
|
|
static void printSummary() {
|
|
if (!_enabled || _results.isEmpty) return;
|
|
|
|
print('\n' + '=' * 60);
|
|
print('PERFORMANCE SUMMARY');
|
|
print('=' * 60);
|
|
|
|
// Trier par durée décroissante
|
|
final sortedResults = _results.entries.toList()
|
|
..sort((a, b) => b.value.compareTo(a.value));
|
|
|
|
for (var entry in sortedResults) {
|
|
final color = _getColorForDuration(entry.value);
|
|
final ms = entry.value.inMilliseconds;
|
|
print('$color ${entry.key.padRight(40)} : ${ms.toString().padLeft(6)}ms');
|
|
}
|
|
|
|
final total = _results.values.fold<Duration>(
|
|
Duration.zero,
|
|
(sum, duration) => sum + duration,
|
|
);
|
|
print('${'=' * 60}');
|
|
print('TOTAL: ${total.inMilliseconds}ms');
|
|
print('=' * 60 + '\n');
|
|
}
|
|
|
|
/// Réinitialise toutes les mesures
|
|
static void reset() {
|
|
_timings.clear();
|
|
_results.clear();
|
|
if (kDebugMode) {
|
|
print('[PerformanceMonitor] 🔄 Reset');
|
|
}
|
|
}
|
|
|
|
/// Retourne une couleur basée sur la durée (pour les logs)
|
|
static String _getColorForDuration(Duration duration) {
|
|
final ms = duration.inMilliseconds;
|
|
if (ms < 100) return '🟢'; // Rapide
|
|
if (ms < 500) return '🟡'; // Moyen
|
|
if (ms < 1000) return '🟠'; // Lent
|
|
return '🔴'; // Très lent
|
|
}
|
|
|
|
/// Mesure une opération asynchrone
|
|
static Future<T> measure<T>(String key, Future<T> Function() operation) async {
|
|
start(key);
|
|
try {
|
|
final result = await operation();
|
|
end(key);
|
|
return result;
|
|
} catch (e) {
|
|
end(key);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
/// Mesure une opération synchrone
|
|
static T measureSync<T>(String key, T Function() operation) {
|
|
start(key);
|
|
try {
|
|
final result = operation();
|
|
end(key);
|
|
return result;
|
|
} catch (e) {
|
|
end(key);
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|
|
|