Livraison d ela gestion des opérations v0.4.0

This commit is contained in:
d6soft
2025-06-24 13:01:43 +02:00
parent b9672a6228
commit 7763d02fae
819 changed files with 306790 additions and 145462 deletions

View File

@@ -0,0 +1,499 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:path_provider/path_provider.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/services/hive_web_fix.dart';
import 'package:geosector_app/core/services/hive_adapters.dart';
// Import de tous les modèles typés
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/chat/models/conversation_model.dart';
import 'package:geosector_app/chat/models/message_model.dart';
/// Service singleton centralisé pour la gestion complète des Box Hive
/// Utilisé par main.dart pour l'initialisation et par logout pour le nettoyage
class HiveService {
static HiveService? _instance;
static HiveService get instance => _instance ??= HiveService._internal();
HiveService._internal();
/// Configuration des Box typées de l'application
static const List<HiveBoxConfig> _boxConfigs = [
HiveBoxConfig<UserModel>(AppKeys.userBoxName, 'UserModel'),
HiveBoxConfig<AmicaleModel>(AppKeys.amicaleBoxName, 'AmicaleModel'),
HiveBoxConfig<ClientModel>(AppKeys.clientsBoxName, 'ClientModel'),
HiveBoxConfig<OperationModel>(AppKeys.operationsBoxName, 'OperationModel'),
HiveBoxConfig<SectorModel>(AppKeys.sectorsBoxName, 'SectorModel'),
HiveBoxConfig<PassageModel>(AppKeys.passagesBoxName, 'PassageModel'),
HiveBoxConfig<MembreModel>(AppKeys.membresBoxName, 'MembreModel'),
HiveBoxConfig<UserSectorModel>(AppKeys.userSectorBoxName, 'UserSectorModel'),
HiveBoxConfig<ConversationModel>(AppKeys.chatConversationsBoxName, 'ConversationModel'),
HiveBoxConfig<MessageModel>(AppKeys.chatMessagesBoxName, 'MessageModel'),
HiveBoxConfig<dynamic>(AppKeys.settingsBoxName, 'Settings'),
HiveBoxConfig<dynamic>(AppKeys.regionsBoxName, 'Regions'),
];
bool _isInitialized = false;
bool get isInitialized => _isInitialized;
// === INITIALISATION COMPLÈTE (appelée par main.dart) ===
/// Initialisation complète de Hive avec réinitialisation totale
Future<void> initializeAndResetHive() async {
if (_isInitialized) {
debugPrint(' HiveService déjà initialisé');
return;
}
try {
debugPrint('🔧 Initialisation complète de Hive avec reset...');
// 1. Initialisation de base de Hive
await Hive.initFlutter();
debugPrint('✅ Hive.initFlutter() terminé');
// 2. Enregistrement des adaptateurs
_registerAdapters();
// 3. Destruction complète des anciennes données
await _destroyAllData();
// 4. Création des Box vides et propres
await _createAllBoxes();
_isInitialized = true;
debugPrint('✅ HiveService initialisé avec succès');
} catch (e) {
debugPrint('❌ Erreur lors de l\'initialisation complète: $e');
_isInitialized = false;
rethrow;
}
}
// === INITIALISATION SIMPLE (appelée par splash_page si besoin) ===
/// Initialisation simple sans reset (utilisée par splash_page si déjà initialisé)
Future<void> ensureBoxesAreOpen() async {
try {
debugPrint('🔍 Vérification et ouverture des Box...');
// Vérifier si toutes les Box sont ouvertes
bool allOpen = true;
for (final config in _boxConfigs) {
if (!Hive.isBoxOpen(config.name)) {
allOpen = false;
break;
}
}
if (allOpen) {
debugPrint('✅ Toutes les Box sont déjà ouvertes');
return;
}
// Ouvrir les Box manquantes
await _createAllBoxes();
debugPrint('✅ Box manquantes ouvertes');
} catch (e) {
debugPrint('❌ Erreur lors de la vérification des Box: $e');
rethrow;
}
}
// === NETTOYAGE LOGOUT (appelé lors du logout) ===
/// Nettoyage sélectif lors du logout (préserve les utilisateurs)
Future<void> cleanDataOnLogout() async {
try {
debugPrint('🧹 Nettoyage des données au logout...');
// Nettoyer toutes les Box sauf les utilisateurs
for (final config in _boxConfigs) {
if (config.name != AppKeys.userBoxName) {
await _clearSingleBox(config.name);
}
}
debugPrint('✅ Nettoyage logout terminé (utilisateurs préservés)');
} catch (e) {
debugPrint('❌ Erreur lors du nettoyage logout: $e');
rethrow;
}
}
// === MÉTHODES PRIVÉES D'INITIALISATION ===
/// Enregistrement de tous les adaptateurs Hive
void _registerAdapters() {
try {
if (!Hive.isAdapterRegistered(0)) {
// Utiliser HiveAdapters existant pour enregistrer tous les adaptateurs
HiveAdapters.registerAll();
debugPrint('🔌 Adaptateurs Hive enregistrés via HiveAdapters');
} else {
debugPrint(' Adaptateurs déjà enregistrés');
}
} catch (e) {
debugPrint('❌ Erreur enregistrement adaptateurs: $e');
// Ne pas faire échouer l'initialisation
}
}
/// Destruction complète de toutes les données selon la plateforme
Future<void> _destroyAllData() async {
try {
debugPrint('💥 Destruction complète des données Hive...');
// 1. Fermer toutes les Box ouvertes
await _closeAllOpenBoxes();
// 2. Suppression selon la plateforme
if (kIsWeb) {
await _destroyDataWeb();
} else if (Platform.isIOS) {
await _destroyDataIOS();
} else if (Platform.isAndroid) {
await _destroyDataAndroid();
} else {
await _destroyDataDesktop();
}
// 3. Attendre pour s'assurer que tout est détruit
await Future.delayed(const Duration(seconds: 1));
debugPrint('✅ Destruction complète terminée');
} catch (e) {
debugPrint('❌ Erreur destruction: $e');
// Continuer malgré l'erreur
}
}
/// Fermeture de toutes les Box ouvertes
Future<void> _closeAllOpenBoxes() async {
try {
debugPrint('🔒 Fermeture de toutes les Box ouvertes...');
// Fermer les Box configurées
for (final config in _boxConfigs) {
try {
if (Hive.isBoxOpen(config.name)) {
await Hive.box(config.name).close();
debugPrint('🔒 Box ${config.name} fermée');
}
} catch (e) {
debugPrint('⚠️ Erreur fermeture ${config.name}: $e');
}
}
// Fermer aussi les Box potentiellement orphelines
final orphanBoxes = ['auth', 'temp', 'cache', 'locations', 'messages'];
for (final boxName in orphanBoxes) {
try {
if (Hive.isBoxOpen(boxName)) {
await Hive.box(boxName).close();
debugPrint('🔒 Box orpheline $boxName fermée');
}
} catch (e) {
debugPrint('⚠️ Erreur fermeture orpheline $boxName: $e');
}
}
} catch (e) {
debugPrint('❌ Erreur fermeture générale: $e');
}
}
/// Destruction des données sur Web
Future<void> _destroyDataWeb() async {
try {
debugPrint('🌐 Destruction Web...');
// Sur Web, utiliser le HiveWebFix si disponible
try {
await HiveWebFix.resetHiveCompletely();
debugPrint('✅ Destruction Web via HiveWebFix');
return;
} catch (e) {
debugPrint('⚠️ HiveWebFix échoué, fallback...');
}
// Fallback : supprimer Box par Box
for (final config in _boxConfigs) {
try {
await Hive.deleteBoxFromDisk(config.name);
debugPrint('🗑️ Box Web ${config.name} supprimée');
} catch (e) {
debugPrint('⚠️ Erreur suppression Web ${config.name}: $e');
}
}
} catch (e) {
debugPrint('❌ Erreur destruction Web: $e');
}
}
/// Destruction des données sur iOS
Future<void> _destroyDataIOS() async {
try {
debugPrint('🍎 Destruction iOS...');
// Méthode 1: Destruction totale
try {
await Hive.deleteFromDisk();
debugPrint('✅ Destruction iOS complète');
return;
} catch (e) {
debugPrint('⚠️ Destruction iOS totale échouée, méthode alternative...');
}
// Méthode 2: Suppression des fichiers manuellement
try {
final appDir = await getApplicationDocumentsDirectory();
final hiveDir = Directory('${appDir.path}/hive');
if (await hiveDir.exists()) {
await hiveDir.delete(recursive: true);
debugPrint('✅ Dossier Hive iOS supprimé');
}
} catch (e) {
debugPrint('⚠️ Suppression dossier iOS échouée: $e');
}
// Méthode 3: Fallback Box par Box
await _fallbackDeleteBoxes();
} catch (e) {
debugPrint('❌ Erreur destruction iOS: $e');
}
}
/// Destruction des données sur Android
Future<void> _destroyDataAndroid() async {
try {
debugPrint('🤖 Destruction Android...');
// Méthode 1: Destruction totale
try {
await Hive.deleteFromDisk();
debugPrint('✅ Destruction Android complète');
return;
} catch (e) {
debugPrint('⚠️ Destruction Android totale échouée, méthode alternative...');
}
// Méthode 2: Suppression des fichiers .hive et .lock
try {
final appDir = await getApplicationDocumentsDirectory();
final files = await appDir.list().toList();
int deletedCount = 0;
for (final file in files) {
final fileName = file.path.split('/').last;
if (fileName.endsWith('.hive') || fileName.endsWith('.lock')) {
try {
await file.delete();
deletedCount++;
} catch (e) {
debugPrint('⚠️ Erreur suppression fichier $fileName: $e');
}
}
}
debugPrint('$deletedCount fichiers Android supprimés');
} catch (e) {
debugPrint('⚠️ Suppression fichiers Android échouée: $e');
}
// Méthode 3: Fallback Box par Box
await _fallbackDeleteBoxes();
} catch (e) {
debugPrint('❌ Erreur destruction Android: $e');
}
}
/// Destruction des données sur Desktop
Future<void> _destroyDataDesktop() async {
try {
debugPrint('🖥️ Destruction Desktop...');
// Destruction totale
await Hive.deleteFromDisk();
debugPrint('✅ Destruction Desktop complète');
} catch (e) {
debugPrint('⚠️ Destruction Desktop échouée, fallback...');
await _fallbackDeleteBoxes();
}
}
/// Fallback : suppression Box par Box
Future<void> _fallbackDeleteBoxes() async {
debugPrint('🔄 Fallback: suppression Box par Box...');
for (final config in _boxConfigs) {
try {
await Hive.deleteBoxFromDisk(config.name);
debugPrint('🗑️ Box fallback ${config.name} supprimée');
} catch (e) {
debugPrint('⚠️ Erreur suppression fallback ${config.name}: $e');
}
}
}
/// Création de toutes les Box vides et propres
Future<void> _createAllBoxes() async {
try {
debugPrint('🆕 Création de toutes les Box...');
for (int i = 0; i < _boxConfigs.length; i++) {
final config = _boxConfigs[i];
try {
await _createSingleBox(config);
debugPrint('✅ Box ${config.name} créée (${i + 1}/${_boxConfigs.length})');
} catch (e) {
debugPrint('❌ Erreur création ${config.name}: $e');
// Continuer même en cas d'erreur
}
// Petite pause entre les créations
await Future.delayed(const Duration(milliseconds: 100));
}
debugPrint('✅ Toutes les Box ont été créées');
} catch (e) {
debugPrint('❌ Erreur création des Box: $e');
rethrow;
}
}
/// Création d'une Box individuelle avec le bon type
Future<void> _createSingleBox(HiveBoxConfig config) async {
try {
if (Hive.isBoxOpen(config.name)) {
debugPrint(' Box ${config.name} déjà ouverte');
return;
}
switch (config.type) {
case 'UserModel':
await Hive.openBox<UserModel>(config.name);
break;
case 'AmicaleModel':
await Hive.openBox<AmicaleModel>(config.name);
break;
case 'ClientModel':
await Hive.openBox<ClientModel>(config.name);
break;
case 'OperationModel':
await Hive.openBox<OperationModel>(config.name);
break;
case 'SectorModel':
await Hive.openBox<SectorModel>(config.name);
break;
case 'PassageModel':
await Hive.openBox<PassageModel>(config.name);
break;
case 'MembreModel':
await Hive.openBox<MembreModel>(config.name);
break;
case 'UserSectorModel':
await Hive.openBox<UserSectorModel>(config.name);
break;
case 'ConversationModel':
await Hive.openBox<ConversationModel>(config.name);
break;
case 'MessageModel':
await Hive.openBox<MessageModel>(config.name);
break;
default:
// Pour Settings, Regions, etc.
await Hive.openBox(config.name);
}
} catch (e) {
debugPrint('❌ Erreur création spécifique ${config.name}: $e');
// Fallback : essayer sans type
try {
await Hive.openBox(config.name);
debugPrint('⚠️ Box ${config.name} créée sans type');
} catch (e2) {
debugPrint('❌ Échec total ${config.name}: $e2');
rethrow;
}
}
}
// === MÉTHODES UTILITAIRES ===
/// Vider une Box individuelle
Future<void> _clearSingleBox(String boxName) async {
try {
if (Hive.isBoxOpen(boxName)) {
await Hive.box(boxName).clear();
debugPrint('🧹 Box $boxName vidée');
} else {
debugPrint(' Box $boxName n\'est pas ouverte, impossible de la vider');
}
} catch (e) {
debugPrint('⚠️ Erreur vidage $boxName: $e');
}
}
/// Vérification que toutes les Box sont ouvertes
bool areAllBoxesOpen() {
for (final config in _boxConfigs) {
if (!Hive.isBoxOpen(config.name)) {
debugPrint('❌ Box ${config.name} n\'est pas ouverte');
return false;
}
}
debugPrint('✅ Toutes les Box sont ouvertes');
return true;
}
/// Récupération sécurisée d'une Box typée
Box<T> getTypedBox<T>(String boxName) {
if (!Hive.isBoxOpen(boxName)) {
throw Exception('La Box $boxName n\'est pas ouverte');
}
return Hive.box<T>(boxName);
}
/// Récupération sécurisée d'une Box non-typée
Box getBox(String boxName) {
if (!Hive.isBoxOpen(boxName)) {
throw Exception('La Box $boxName n\'est pas ouverte');
}
return Hive.box(boxName);
}
/// Liste des noms de toutes les Box configurées
List<String> getAllBoxNames() {
return _boxConfigs.map((config) => config.name).toList();
}
/// Diagnostic complet de l'état des Box
Map<String, bool> getDiagnostic() {
final diagnostic = <String, bool>{};
for (final config in _boxConfigs) {
diagnostic[config.name] = Hive.isBoxOpen(config.name);
}
return diagnostic;
}
/// Reset complet du service (pour tests)
static void reset() {
_instance = null;
}
}
/// Configuration d'une Box Hive avec type
class HiveBoxConfig<T> {
final String name;
final String type;
const HiveBoxConfig(this.name, this.type);
}