✅ NOUVEAU SERVICE CRÉÉ: - DataLoadingService: gère tout le chargement des données au login - Sépare les responsabilités: UserRepository se concentre sur l'auth - Simplification massive du code de connexion ✅ USERREPOSITORY REFACTORISÉ: - Suppression de toute la logique de chargement de données (déplacée vers DataLoadingService) - Délégation complète aux services singleton (CurrentUserService, CurrentAmicaleService) - Constructeur ultra-simplifié (plus d'injection ApiService) - Méthodes d'auth optimisées et clarifiées ✅ REPOSITORIES SIMPLIFIÉS: - AmicaleRepository: constructeur sans paramètres, ApiService.instance - ClientRepository: même pattern de simplification - MembreRepository: suppression injection, getters sécurisés - OperationRepository: utilisation ApiService.instance - PassageRepository: simplification massive, nouveau pattern - SectorRepository: optimisation et nouvelle structure ✅ ARCHITECTURE SINGLETONS: - ApiService: pattern singleton thread-safe - CurrentUserService: gestion utilisateur connecté + persistence Hive (Box user) - CurrentAmicaleService: gestion amicale courante + auto-sync - Box Hive 'users' renommée en 'user' avec migration automatique ✅ APP.DART & MAIN.DART: - Suppression injections multiples dans repositories - Intégration des services singleton dans main.dart - Router simplifié avec CurrentUserService État: Architecture singleton opérationnelle, prêt pour tests et widgets
256 lines
8.8 KiB
Dart
256 lines
8.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
|
import 'package:flutter_web_plugins/url_strategy.dart';
|
|
import 'package:geosector_app/core/services/app_info_service.dart';
|
|
import 'package:geosector_app/core/services/api_service.dart';
|
|
import 'package:geosector_app/core/services/current_user_service.dart';
|
|
import 'package:geosector_app/core/services/current_amicale_service.dart';
|
|
import 'package:geosector_app/app.dart';
|
|
import 'package:hive_flutter/hive_flutter.dart';
|
|
import 'package:geosector_app/core/data/models/user_model.dart';
|
|
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
|
import 'package:geosector_app/core/data/models/client_model.dart';
|
|
import 'package:geosector_app/core/data/models/operation_model.dart';
|
|
import 'package:geosector_app/core/data/models/sector_model.dart';
|
|
import 'package:geosector_app/core/data/models/passage_model.dart';
|
|
import 'package:geosector_app/core/data/models/membre_model.dart';
|
|
import 'package:geosector_app/core/data/models/user_sector_model.dart';
|
|
import 'package:geosector_app/core/data/models/region_model.dart';
|
|
import 'package:geosector_app/core/constants/app_keys.dart';
|
|
import 'package:geosector_app/core/services/hive_reset_state_service.dart';
|
|
import 'package:geosector_app/chat/models/chat_adapters.dart';
|
|
|
|
void main() async {
|
|
// IMPORTANT: Configurer l'URL strategy pour éviter les # dans les URLs
|
|
usePathUrlStrategy();
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
// Initialiser les services essentiels
|
|
await _initializeServices();
|
|
|
|
// Initialiser Hive avec gestion des erreurs
|
|
final hiveInitialized = await _initializeHive();
|
|
|
|
// TEMPORAIREMENT: Ne pas marquer l'erreur pour éviter la redirection
|
|
// if (!hiveInitialized) {
|
|
// debugPrint('Incompatibilité détectée dans les données Hive. Marquage pour affichage du dialogue...');
|
|
// hiveResetStateService.markAsReset();
|
|
// }
|
|
|
|
// Configurer l'orientation de l'application (mobile uniquement)
|
|
if (!kIsWeb) {
|
|
await SystemChrome.setPreferredOrientations([
|
|
DeviceOrientation.portraitUp,
|
|
DeviceOrientation.portraitDown,
|
|
]);
|
|
}
|
|
|
|
// Lancer l'application
|
|
runApp(const GeosectorApp());
|
|
}
|
|
|
|
/// Initialise les services essentiels
|
|
Future<void> _initializeServices() async {
|
|
try {
|
|
// Initialiser ApiService en premier
|
|
await ApiService.initialize();
|
|
debugPrint('✅ ApiService singleton initialisé');
|
|
|
|
// Les services CurrentUserService et CurrentAmicaleService s'initialisent automatiquement
|
|
// au premier accès via le pattern singleton lazy
|
|
debugPrint('✅ CurrentUserService prêt');
|
|
debugPrint('✅ CurrentAmicaleService prêt');
|
|
|
|
await AppInfoService.initialize();
|
|
debugPrint('✅ Tous les services initialisés avec succès');
|
|
} catch (e) {
|
|
debugPrint('❌ Erreur lors de l\'initialisation des services: $e');
|
|
rethrow; // Important pour arrêter l'app si les services critiques échouent
|
|
}
|
|
}
|
|
|
|
/// Initialise Hive et les adaptateurs
|
|
Future<bool> _initializeHive() async {
|
|
try {
|
|
// Initialiser Hive
|
|
await Hive.initFlutter();
|
|
|
|
// Enregistrer les adaptateurs Hive pour les modèles principaux
|
|
_registerHiveAdapters();
|
|
|
|
// Ouvrir uniquement les boîtes essentielles au démarrage
|
|
await _openEssentialHiveBoxes();
|
|
|
|
// Charger les données depuis Hive au démarrage
|
|
await CurrentUserService.instance.loadFromHive();
|
|
await CurrentAmicaleService.instance.loadFromHive();
|
|
debugPrint('✅ Données utilisateur/amicale chargées depuis Hive');
|
|
|
|
debugPrint('Hive initialisé avec succès');
|
|
return true;
|
|
} catch (e) {
|
|
debugPrint('Erreur lors de l\'initialisation de Hive: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Enregistre tous les adaptateurs Hive
|
|
void _registerHiveAdapters() {
|
|
// Vérifier si les adaptateurs sont déjà enregistrés pour éviter les doublons
|
|
if (!Hive.isAdapterRegistered(0)) {
|
|
Hive.registerAdapter(UserModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(1)) {
|
|
Hive.registerAdapter(AmicaleModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(2)) {
|
|
Hive.registerAdapter(ClientModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(3)) {
|
|
Hive.registerAdapter(OperationModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(4)) {
|
|
Hive.registerAdapter(SectorModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(5)) {
|
|
Hive.registerAdapter(PassageModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(6)) {
|
|
Hive.registerAdapter(MembreModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(7)) {
|
|
Hive.registerAdapter(UserSectorModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(8)) {
|
|
Hive.registerAdapter(RegionModelAdapter());
|
|
}
|
|
|
|
// Modèles de chat
|
|
if (!Hive.isAdapterRegistered(9)) {
|
|
Hive.registerAdapter(ConversationModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(10)) {
|
|
Hive.registerAdapter(MessageModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(11)) {
|
|
Hive.registerAdapter(ParticipantModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(12)) {
|
|
Hive.registerAdapter(AnonymousUserModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(13)) {
|
|
Hive.registerAdapter(AudienceTargetModelAdapter());
|
|
}
|
|
if (!Hive.isAdapterRegistered(14)) {
|
|
Hive.registerAdapter(NotificationSettingsAdapter());
|
|
}
|
|
}
|
|
|
|
/// Ouvre les boîtes Hive essentielles avec migration users -> user
|
|
Future<void> _openEssentialHiveBoxes() async {
|
|
final boxesToOpen = [
|
|
{'name': AppKeys.userBoxName, 'type': 'UserModel'},
|
|
{'name': AppKeys.amicaleBoxName, 'type': 'AmicaleModel'},
|
|
{'name': AppKeys.clientsBoxName, 'type': 'ClientModel'},
|
|
{'name': AppKeys.settingsBoxName, 'type': 'dynamic'},
|
|
{'name': AppKeys.chatConversationsBoxName, 'type': 'ConversationModel'},
|
|
{'name': AppKeys.chatMessagesBoxName, 'type': 'MessageModel'},
|
|
];
|
|
|
|
// Logique de migration de l'ancienne box users vers user
|
|
try {
|
|
// Vérifier si l'ancienne box users existe
|
|
if (await _doesBoxExist(AppKeys.usersBoxNameOld)) {
|
|
debugPrint('🔄 Migration détectée: box users -> user');
|
|
|
|
// Ouvrir l'ancienne box
|
|
final oldBox = await Hive.openBox<UserModel>(AppKeys.usersBoxNameOld);
|
|
|
|
// Ouvrir la nouvelle box
|
|
final newBox = await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
|
|
|
// Migrer les données si la nouvelle box est vide
|
|
if (oldBox.isNotEmpty && newBox.isEmpty) {
|
|
debugPrint('📦 Migration des données users -> user...');
|
|
|
|
// Chercher l'utilisateur actuel dans l'ancienne box
|
|
final userData = oldBox.get('current_user') ?? oldBox.values.firstOrNull;
|
|
if (userData != null) {
|
|
await newBox.put('current_user', userData);
|
|
debugPrint('✅ Migration de users -> user réussie pour ${userData.email}');
|
|
}
|
|
}
|
|
|
|
// Fermer et supprimer l'ancienne box
|
|
await oldBox.close();
|
|
await Hive.deleteBoxFromDisk(AppKeys.usersBoxNameOld);
|
|
debugPrint('🗑️ Ancienne box users supprimée');
|
|
} else {
|
|
// Ouvrir normalement la nouvelle box
|
|
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
|
}
|
|
} catch (e) {
|
|
debugPrint('⚠️ Erreur migration box users: $e');
|
|
// En cas d'erreur, ouvrir quand même la nouvelle box
|
|
try {
|
|
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
|
} catch (e2) {
|
|
debugPrint('❌ Impossible d\'ouvrir la box user: $e2');
|
|
}
|
|
}
|
|
|
|
// Ouvrir les autres boîtes
|
|
for (final box in boxesToOpen) {
|
|
try {
|
|
final boxName = box['name'] as String;
|
|
final boxType = box['type'] as String;
|
|
|
|
// Skip userBoxName car déjà traité dans la migration
|
|
if (boxName == AppKeys.userBoxName) continue;
|
|
|
|
// Vérifier si la boîte est déjà ouverte
|
|
if (Hive.isBoxOpen(boxName)) {
|
|
debugPrint('📦 Boîte $boxName déjà ouverte');
|
|
continue;
|
|
}
|
|
|
|
switch (boxType) {
|
|
case 'AmicaleModel':
|
|
await Hive.openBox<AmicaleModel>(boxName);
|
|
break;
|
|
case 'ClientModel':
|
|
await Hive.openBox<ClientModel>(boxName);
|
|
break;
|
|
case 'ConversationModel':
|
|
await Hive.openBox<ConversationModel>(boxName);
|
|
break;
|
|
case 'MessageModel':
|
|
await Hive.openBox<MessageModel>(boxName);
|
|
break;
|
|
default:
|
|
await Hive.openBox(boxName);
|
|
}
|
|
|
|
debugPrint('✅ Boîte $boxName ouverte avec succès');
|
|
} catch (e) {
|
|
debugPrint('❌ Erreur lors de l\'ouverture de la boîte ${box['name']}: $e');
|
|
// Ne pas lancer d'erreur, continuer avec les autres boîtes
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Vérifie si une box Hive existe sur le disque
|
|
Future<bool> _doesBoxExist(String boxName) async {
|
|
try {
|
|
// Tentative d'ouverture pour vérifier l'existence
|
|
final box = await Hive.openBox<UserModel>(boxName);
|
|
final exists = box.isNotEmpty;
|
|
await box.close();
|
|
return exists;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|