feat: création services singleton et renommage Box
Services créés: ✅ CurrentUserService singleton pour utilisateur connecté ✅ CurrentAmicaleService singleton pour amicale courante ✅ ApiService transformé en singleton Box Hive: ✅ Renommage users -> user (plus logique) ✅ Migration automatique des données ✅ Services intégrés dans main.dart État: Services créés, prêt pour refactorisation repositories
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
/// Fichier contenant toutes les constantes utilisées dans l'application
|
||||
/// Centralise les clés, noms de boîtes Hive, et autres constantes
|
||||
/// pour faciliter la maintenance et éviter les erreurs de frappe
|
||||
library;
|
||||
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppKeys {
|
||||
// Noms des boîtes Hive
|
||||
static const String usersBoxName = 'users';
|
||||
static const String userBoxName = 'user';
|
||||
static const String usersBoxNameOld = 'users';
|
||||
static const String amicaleBoxName = 'amicale';
|
||||
static const String clientsBoxName = 'clients';
|
||||
static const String operationsBoxName = 'operations';
|
||||
@@ -49,12 +51,9 @@ class AppKeys {
|
||||
static const Duration sessionDefaultExpiry = Duration(days: 7);
|
||||
|
||||
// Clés API externes
|
||||
static const String mapboxApiKeyDev =
|
||||
'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY21hanVmNjN5MTM5djJtczdsMW92cjQ0ciJ9.pUCMuvWPB3cuBaPh4ywTAw';
|
||||
static const String mapboxApiKeyRec =
|
||||
'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY21hanVlZ3FiMGx0NDJpc2k4YnkxaWZ2dSJ9.OqGJtjlWRgB4fIjECCB8WA';
|
||||
static const String mapboxApiKeyProd =
|
||||
'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY204dTNhNmd0MGV1ZzJqc2pnNnB0NjYxdSJ9.TA5Mvliyn91Oi01F_2Yuxw';
|
||||
static const String mapboxApiKeyDev = 'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY21hanVmNjN5MTM5djJtczdsMW92cjQ0ciJ9.pUCMuvWPB3cuBaPh4ywTAw';
|
||||
static const String mapboxApiKeyRec = 'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY21hanVlZ3FiMGx0NDJpc2k4YnkxaWZ2dSJ9.OqGJtjlWRgB4fIjECCB8WA';
|
||||
static const String mapboxApiKeyProd = 'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY204dTNhNmd0MGV1ZzJqc2pnNnB0NjYxdSJ9.TA5Mvliyn91Oi01F_2Yuxw';
|
||||
|
||||
// Méthode pour obtenir la clé API Mapbox en fonction de l'environnement actuel
|
||||
static String getMapboxApiKey(String environment) {
|
||||
|
||||
@@ -49,9 +49,8 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
|
||||
// Utilisation de getters lazy pour n'accéder aux boîtes que lorsque nécessaire
|
||||
Box<UserModel> get _userBox => Hive.box<UserModel>(AppKeys.usersBoxName);
|
||||
Box<AmicaleModel> get _amicaleBox =>
|
||||
Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||
Box<UserModel> get _userBox => Hive.box<UserModel>(AppKeys.userBoxName);
|
||||
Box<AmicaleModel> get _amicaleBox => Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||
|
||||
// Getters pour les autres boîtes qui vérifient si elles sont ouvertes avant accès
|
||||
Box<OperationModel> get _operationBox {
|
||||
@@ -118,10 +117,7 @@ class UserRepository extends ChangeNotifier {
|
||||
bool _isLoading = false;
|
||||
|
||||
UserRepository(this._apiService,
|
||||
{SyncService? syncService,
|
||||
OperationRepository? operationRepository,
|
||||
SectorRepository? sectorRepository,
|
||||
PassageRepository? passageRepository})
|
||||
{SyncService? syncService, OperationRepository? operationRepository, SectorRepository? sectorRepository, PassageRepository? passageRepository})
|
||||
: _syncService = syncService,
|
||||
_operationRepository = operationRepository,
|
||||
_sectorRepository = sectorRepository,
|
||||
@@ -160,7 +156,7 @@ class UserRepository extends ChangeNotifier {
|
||||
if (user.role is String) {
|
||||
return int.tryParse(user.role as String) ?? 1;
|
||||
} else {
|
||||
return user.role as int;
|
||||
return user.role;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,15 +164,13 @@ class UserRepository extends ChangeNotifier {
|
||||
UserModel? _getCurrentUserFromStorage() {
|
||||
try {
|
||||
// Vérifier d'abord si la boîte est ouverte
|
||||
if (!Hive.isBoxOpen(AppKeys.usersBoxName)) {
|
||||
if (!Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||
debugPrint('Boîte users non ouverte, tentative d\'ouverture...');
|
||||
return null; // Retourner null plutôt que d'essayer d'ouvrir ici
|
||||
}
|
||||
|
||||
// Chercher un utilisateur avec une session active
|
||||
final activeUsers = _userBox.values
|
||||
.where((user) => user.sessionId != null && user.sessionId!.isNotEmpty)
|
||||
.toList();
|
||||
final activeUsers = _userBox.values.where((user) => user.sessionId != null && user.sessionId!.isNotEmpty).toList();
|
||||
|
||||
// S'il y a des utilisateurs actifs, retourner le premier
|
||||
if (activeUsers.isNotEmpty) {
|
||||
@@ -185,8 +179,7 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la récupération de l\'utilisateur depuis le stockage: $e');
|
||||
debugPrint('Erreur lors de la récupération de l\'utilisateur depuis le stockage: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -218,8 +211,7 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
|
||||
// Login API PHP
|
||||
Future<Map<String, dynamic>> loginAPI(String username, String password,
|
||||
{required String type}) async {
|
||||
Future<Map<String, dynamic>> loginAPI(String username, String password, {required String type}) async {
|
||||
try {
|
||||
return await _apiService.login(username, password, type: type);
|
||||
} catch (e) {
|
||||
@@ -229,19 +221,11 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
|
||||
// Register API PHP - Uniquement pour les administrateurs
|
||||
Future<Map<String, dynamic>> registerAPI(String email, String name,
|
||||
String amicaleName, String postalCode, String cityName) async {
|
||||
Future<Map<String, dynamic>> registerAPI(String email, String name, String amicaleName, String postalCode, String cityName) async {
|
||||
try {
|
||||
final Map<String, dynamic> data = {
|
||||
'email': email,
|
||||
'name': name,
|
||||
'amicale_name': amicaleName,
|
||||
'postal_code': postalCode,
|
||||
'city_name': cityName
|
||||
};
|
||||
final Map<String, dynamic> data = {'email': email, 'name': name, 'amicale_name': amicaleName, 'postal_code': postalCode, 'city_name': cityName};
|
||||
|
||||
final response =
|
||||
await _apiService.post(AppKeys.registerEndpoint, data: data);
|
||||
final response = await _apiService.post(AppKeys.registerEndpoint, data: data);
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
debugPrint('Erreur register API: $e');
|
||||
@@ -270,20 +254,16 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
|
||||
// Méthode d'inscription (uniquement pour les administrateurs)
|
||||
Future<bool> register(String email, String password, String name,
|
||||
String amicaleName, String postalCode, String cityName) async {
|
||||
Future<bool> register(String email, String password, String name, String amicaleName, String postalCode, String cityName) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
// Enregistrer l'administrateur via l'API
|
||||
final apiResult =
|
||||
await registerAPI(email, name, amicaleName, postalCode, cityName);
|
||||
final apiResult = await registerAPI(email, name, amicaleName, postalCode, cityName);
|
||||
|
||||
// Créer l'administrateur local
|
||||
final int userId = apiResult['user_id'] is String
|
||||
? int.parse(apiResult['user_id'])
|
||||
: apiResult['user_id'];
|
||||
final int userId = apiResult['user_id'] is String ? int.parse(apiResult['user_id']) : apiResult['user_id'];
|
||||
final now = DateTime.now();
|
||||
final newAdmin = UserModel(
|
||||
id: userId,
|
||||
@@ -316,8 +296,7 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
|
||||
// Login complet avec suivi de progression
|
||||
Future<bool> login(String username, String password,
|
||||
{required String type}) async {
|
||||
Future<bool> login(String username, String password, {required String type}) async {
|
||||
_isLoading = true;
|
||||
_updateLoadingState(LoadingState.initial.copyWith(
|
||||
message: 'Connexion en cours...',
|
||||
@@ -346,8 +325,7 @@ class UserRepository extends ChangeNotifier {
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
debugPrint('Nettoyage: Box $boxName supprimée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||
debugPrint('Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,8 +339,7 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
// Sur le web, utiliser notre méthode sécurisée pour nettoyer les boîtes Hive
|
||||
if (kIsWeb) {
|
||||
await HiveWebFix.safeCleanHiveBoxes(
|
||||
excludeBoxes: [AppKeys.usersBoxName]);
|
||||
await HiveWebFix.safeCleanHiveBoxes(excludeBoxes: [AppKeys.userBoxName]);
|
||||
}
|
||||
// Sur iOS, nettoyer les fichiers Hive directement
|
||||
else if (!kIsWeb && Platform.isIOS) {
|
||||
@@ -403,8 +380,7 @@ class UserRepository extends ChangeNotifier {
|
||||
// Si le statut n'est pas 'success', retourner false
|
||||
if (status != 'success') {
|
||||
debugPrint('Échec de connexion: $message');
|
||||
_updateLoadingState(
|
||||
LoadingState.error(message ?? 'Échec de connexion'));
|
||||
_updateLoadingState(LoadingState.error(message ?? 'Échec de connexion'));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -421,8 +397,7 @@ class UserRepository extends ChangeNotifier {
|
||||
});
|
||||
|
||||
// Si la clé 'user' existe, examiner son contenu
|
||||
if (apiResult['user'] != null &&
|
||||
apiResult['user'] is Map<String, dynamic>) {
|
||||
if (apiResult['user'] != null && apiResult['user'] is Map<String, dynamic>) {
|
||||
debugPrint('Détails utilisateur:');
|
||||
final userDetails = apiResult['user'] as Map<String, dynamic>;
|
||||
userDetails.forEach((key, value) {
|
||||
@@ -430,8 +405,7 @@ class UserRepository extends ChangeNotifier {
|
||||
});
|
||||
|
||||
// Construire un UserModel à partir des données utilisateur
|
||||
final user = _processUserData(
|
||||
userDetails, apiResult['session_id'], apiResult['session_expiry']);
|
||||
final user = _processUserData(userDetails, apiResult['session_id'], apiResult['session_expiry']);
|
||||
|
||||
// Supprimer les anciennes références à interface et utiliser directement le rôle
|
||||
await saveUser(user);
|
||||
@@ -463,8 +437,7 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
if (apiResult['clients'] is List) {
|
||||
clientsList = apiResult['clients'] as List<dynamic>;
|
||||
} else if (apiResult['clients'] is Map &&
|
||||
apiResult['clients'].containsKey('data')) {
|
||||
} else if (apiResult['clients'] is Map && apiResult['clients'].containsKey('data')) {
|
||||
clientsList = apiResult['clients']['data'] as List<dynamic>;
|
||||
} else {
|
||||
debugPrint('Format de données de clients non reconnu');
|
||||
@@ -529,8 +502,7 @@ class UserRepository extends ChangeNotifier {
|
||||
));
|
||||
|
||||
// Traitement des membres
|
||||
if (apiResult.containsKey('membres') ||
|
||||
apiResult.containsKey('members')) {
|
||||
if (apiResult.containsKey('membres') || apiResult.containsKey('members')) {
|
||||
final membresData = apiResult['membres'] ?? apiResult['members'];
|
||||
if (membresData != null) {
|
||||
await _processMembres(membresData);
|
||||
@@ -547,8 +519,7 @@ class UserRepository extends ChangeNotifier {
|
||||
// Traitement des associations utilisateurs-secteurs
|
||||
if (apiResult.containsKey('users_sectors')) {
|
||||
await _processUserSectors(apiResult['users_sectors']);
|
||||
debugPrint(
|
||||
'Nombre d\'associations utilisateurs-secteurs chargées: ${_userSectorBox.length}');
|
||||
debugPrint('Nombre d\'associations utilisateurs-secteurs chargées: ${_userSectorBox.length}');
|
||||
}
|
||||
|
||||
// Vérification finale du remplissage des boîtes
|
||||
@@ -570,8 +541,7 @@ class UserRepository extends ChangeNotifier {
|
||||
for (final userSector in _userSectorBox.values) {
|
||||
if (displayCount < 5) {
|
||||
// Limiter à 5 pour éviter de surcharger la console
|
||||
debugPrint(
|
||||
' User ${userSector.id} (${userSector.firstName}) -> Secteur ${userSector.fkSector} (${userSector.name})');
|
||||
debugPrint(' User ${userSector.id} (${userSector.firstName}) -> Secteur ${userSector.fkSector} (${userSector.name})');
|
||||
displayCount++;
|
||||
} else {
|
||||
debugPrint(' ... et ${userSectorCount - 5} autres associations');
|
||||
@@ -591,27 +561,21 @@ class UserRepository extends ChangeNotifier {
|
||||
if (apiResult.containsKey('passages')) {
|
||||
if (apiResult['passages'] is List) {
|
||||
passagesCountInResponse = (apiResult['passages'] as List).length;
|
||||
} else if (apiResult['passages'] is Map &&
|
||||
apiResult['passages'].containsKey('data')) {
|
||||
passagesCountInResponse =
|
||||
(apiResult['passages']['data'] as List).length;
|
||||
} else if (apiResult['passages'] is Map && apiResult['passages'].containsKey('data')) {
|
||||
passagesCountInResponse = (apiResult['passages']['data'] as List).length;
|
||||
}
|
||||
}
|
||||
|
||||
int passagesCountInBox = _passageBox.length;
|
||||
debugPrint(
|
||||
'Nombre de passages dans la réponse API: $passagesCountInResponse');
|
||||
debugPrint('Nombre de passages dans la réponse API: $passagesCountInResponse');
|
||||
debugPrint('Nombre de passages dans la Hive Box: $passagesCountInBox');
|
||||
|
||||
// Si les nombres ne correspondent pas, attendre un peu et revérifier
|
||||
if (passagesCountInResponse > 0 &&
|
||||
passagesCountInBox < passagesCountInResponse) {
|
||||
debugPrint(
|
||||
'Attente supplémentaire pour finaliser le chargement des passages...');
|
||||
if (passagesCountInResponse > 0 && passagesCountInBox < passagesCountInResponse) {
|
||||
debugPrint('Attente supplémentaire pour finaliser le chargement des passages...');
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
passagesCountInBox = _passageBox.length;
|
||||
debugPrint(
|
||||
'Après attente: Nombre de passages dans la Hive Box: $passagesCountInBox');
|
||||
debugPrint('Après attente: Nombre de passages dans la Hive Box: $passagesCountInBox');
|
||||
}
|
||||
|
||||
// Étape 12: Chargement terminé (100%)
|
||||
@@ -652,7 +616,7 @@ class UserRepository extends ChangeNotifier {
|
||||
await Hive.openBox<OperationModel>(boxName);
|
||||
} else if (boxName == AppKeys.sectorsBoxName) {
|
||||
await Hive.openBox<SectorModel>(boxName);
|
||||
} else if (boxName == AppKeys.usersBoxName) {
|
||||
} else if (boxName == AppKeys.userBoxName) {
|
||||
await Hive.openBox<UserModel>(boxName);
|
||||
} else if (boxName == AppKeys.membresBoxName) {
|
||||
await Hive.openBox<MembreModel>(boxName);
|
||||
@@ -696,15 +660,13 @@ class UserRepository extends ChangeNotifier {
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
debugPrint('Nettoyage: Box $boxName supprimée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||
debugPrint('Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Sur le web, utiliser notre méthode sécurisée pour nettoyer les boîtes Hive
|
||||
if (kIsWeb) {
|
||||
await HiveWebFix.safeCleanHiveBoxes(
|
||||
excludeBoxes: [AppKeys.usersBoxName]);
|
||||
await HiveWebFix.safeCleanHiveBoxes(excludeBoxes: [AppKeys.userBoxName]);
|
||||
}
|
||||
// Sur iOS, nettoyer les fichiers Hive directement
|
||||
else if (Platform.isIOS) {
|
||||
@@ -758,8 +720,7 @@ class UserRepository extends ChangeNotifier {
|
||||
try {
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
} catch (deleteError) {
|
||||
debugPrint(
|
||||
'Impossible de supprimer la boîte $boxName: $deleteError');
|
||||
debugPrint('Impossible de supprimer la boîte $boxName: $deleteError');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -854,15 +815,13 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
// Si la boîte contient des éléments, c'est anormal après recréation
|
||||
if (count > 0) {
|
||||
debugPrint(
|
||||
'ATTENTION: La boîte $boxName contient encore des données après recréation');
|
||||
debugPrint('ATTENTION: La boîte $boxName contient encore des données après recréation');
|
||||
// Essayer de vider la boîte une dernière fois
|
||||
await box.clear();
|
||||
debugPrint('Vidage forcé de la boîte $boxName effectué');
|
||||
}
|
||||
} catch (typeError) {
|
||||
debugPrint(
|
||||
'Erreur de typage lors de la vérification de $boxName: $typeError');
|
||||
debugPrint('Erreur de typage lors de la vérification de $boxName: $typeError');
|
||||
|
||||
// Tentative alternative sans typage spécifique
|
||||
try {
|
||||
@@ -872,17 +831,14 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
if (count > 0) {
|
||||
await box.clear();
|
||||
debugPrint(
|
||||
'Vidage forcé de la boîte $boxName (sans typage) effectué');
|
||||
debugPrint('Vidage forcé de la boîte $boxName (sans typage) effectué');
|
||||
}
|
||||
} catch (e2) {
|
||||
debugPrint(
|
||||
'Impossible de vérifier la boîte $boxName même sans typage: $e2');
|
||||
debugPrint('Impossible de vérifier la boîte $boxName même sans typage: $e2');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugPrint(
|
||||
'Boîte $boxName non ouverte, impossible de vérifier l\'intégrité');
|
||||
debugPrint('Boîte $boxName non ouverte, impossible de vérifier l\'intégrité');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la vérification de la boîte $boxName: $e');
|
||||
@@ -891,8 +847,7 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
debugPrint('Vérification d\'intégrité terminée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la vérification d\'intégrité des boîtes Hive: $e');
|
||||
debugPrint('Erreur lors de la vérification d\'intégrité des boîtes Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,7 +861,7 @@ class UserRepository extends ChangeNotifier {
|
||||
'''
|
||||
var request = indexedDB.deleteDatabase("geosector_app");
|
||||
request.onsuccess = function() { console.log("IndexedDB nettoyé avec succès"); };
|
||||
request.onerror = function() { console.log("Erreur lors du nettoyage d\'IndexedDB"); };
|
||||
request.onerror = function() { console.log("Erreur lors du nettoyage d'IndexedDB"); };
|
||||
'''
|
||||
]);
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
@@ -932,7 +887,7 @@ class UserRepository extends ChangeNotifier {
|
||||
for (var entry in entries) {
|
||||
final name = entry.path.split('/').last;
|
||||
// Ne pas supprimer la boîte des utilisateurs
|
||||
if (!name.contains(AppKeys.usersBoxName)) {
|
||||
if (!name.contains(AppKeys.userBoxName)) {
|
||||
debugPrint('Suppression de: ${entry.path}');
|
||||
if (entry is Directory) {
|
||||
await entry.delete(recursive: true);
|
||||
@@ -957,7 +912,7 @@ class UserRepository extends ChangeNotifier {
|
||||
try {
|
||||
debugPrint('Nettoyage des fichiers Hive sur Android...');
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
final hiveDir = Directory('${appDir.path}');
|
||||
final hiveDir = Directory(appDir.path);
|
||||
|
||||
if (await hiveDir.exists()) {
|
||||
debugPrint('Recherche des fichiers Hive dans: ${hiveDir.path}');
|
||||
@@ -968,8 +923,7 @@ class UserRepository extends ChangeNotifier {
|
||||
for (var entry in entries) {
|
||||
final name = entry.path.split('/').last;
|
||||
// Ne supprimer que les fichiers Hive, mais pas la boîte des utilisateurs
|
||||
if (name.endsWith('.hive') &&
|
||||
!name.contains(AppKeys.usersBoxName)) {
|
||||
if (name.endsWith('.hive') && !name.contains(AppKeys.userBoxName)) {
|
||||
debugPrint('Suppression du fichier Hive: ${entry.path}');
|
||||
if (entry is File) {
|
||||
await entry.delete();
|
||||
@@ -985,23 +939,19 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
'Nettoyage des fichiers Hive sur Android terminé. $filesDeleted fichiers supprimés.');
|
||||
debugPrint('Nettoyage des fichiers Hive sur Android terminé. $filesDeleted fichiers supprimés.');
|
||||
} else {
|
||||
debugPrint('Répertoire d\'application non trouvé');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors du nettoyage des fichiers Hive sur Android: $e');
|
||||
debugPrint('Erreur lors du nettoyage des fichiers Hive sur Android: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Méthode de connexion avec affichage d'un overlay de chargement avec progression
|
||||
/// Cette méthode remplace AuthService.login et utilise le nouvel overlay avec barre de progression
|
||||
Future<bool> loginWithUI(
|
||||
BuildContext context, String username, String password,
|
||||
{required String type}) async {
|
||||
Future<bool> loginWithUI(BuildContext context, String username, String password, {required String type}) async {
|
||||
try {
|
||||
// Réinitialiser l'état de chargement
|
||||
_updateLoadingState(LoadingState.initial.copyWith(
|
||||
@@ -1019,7 +969,7 @@ class UserRepository extends ChangeNotifier {
|
||||
);
|
||||
|
||||
// Écouter les changements d'état pour mettre à jour l'overlay
|
||||
final listener = () {
|
||||
listener() {
|
||||
if (_progressOverlay != null) {
|
||||
// Mettre à jour l'overlay avec les nouvelles valeurs
|
||||
LoadingProgressOverlayUtils.update(
|
||||
@@ -1029,7 +979,7 @@ class UserRepository extends ChangeNotifier {
|
||||
stepDescription: _loadingState.stepDescription,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Ajouter l'écouteur
|
||||
addListener(listener);
|
||||
@@ -1164,24 +1114,21 @@ class UserRepository extends ChangeNotifier {
|
||||
String? lastUsername;
|
||||
int? lastRole;
|
||||
UserModel? lastUser;
|
||||
if (Hive.isBoxOpen(AppKeys.usersBoxName) && _userBox.isNotEmpty) {
|
||||
if (Hive.isBoxOpen(AppKeys.userBoxName) && _userBox.isNotEmpty) {
|
||||
try {
|
||||
// Récupérer l'utilisateur actuel ou le dernier utilisateur connecté
|
||||
lastUser = getCurrentUser() ?? _userBox.values.first;
|
||||
if (lastUser != null) {
|
||||
lastUsername = lastUser.username;
|
||||
lastUsername = lastUser.username;
|
||||
|
||||
// Convertir le rôle en int si nécessaire
|
||||
if (lastUser.role is String) {
|
||||
lastRole = int.tryParse(lastUser.role as String) ?? 0;
|
||||
} else {
|
||||
lastRole = lastUser.role as int;
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
'Username sauvegardé pour pré-remplissage: $lastUsername');
|
||||
debugPrint('Rôle sauvegardé pour pré-remplissage: $lastRole');
|
||||
// Convertir le rôle en int si nécessaire
|
||||
if (lastUser.role is String) {
|
||||
lastRole = int.tryParse(lastUser.role as String) ?? 0;
|
||||
} else {
|
||||
lastRole = lastUser.role;
|
||||
}
|
||||
|
||||
debugPrint('Username sauvegardé pour pré-remplissage: $lastUsername');
|
||||
debugPrint('Rôle sauvegardé pour pré-remplissage: $lastRole');
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la sauvegarde du username et du rôle: $e');
|
||||
}
|
||||
@@ -1189,7 +1136,7 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
// 1. Vider toutes les boîtes sans les fermer
|
||||
debugPrint('Vidage des boîtes Hive...');
|
||||
if (Hive.isBoxOpen(AppKeys.usersBoxName)) {
|
||||
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||
try {
|
||||
await _userBox.clear();
|
||||
debugPrint('Boîte users vidée');
|
||||
@@ -1200,16 +1147,14 @@ class UserRepository extends ChangeNotifier {
|
||||
id: lastUser?.id ?? DateTime.now().millisecondsSinceEpoch,
|
||||
email: lastUser?.email ?? '',
|
||||
username: lastUsername,
|
||||
role: lastRole ??
|
||||
0, // Conserver le rôle pour la vérification dans la page de login
|
||||
role: lastRole ?? 0, // Conserver le rôle pour la vérification dans la page de login
|
||||
createdAt: DateTime.now(),
|
||||
lastSyncedAt: DateTime.now(),
|
||||
isActive: false,
|
||||
isSynced: false,
|
||||
);
|
||||
await _userBox.put(minimalUser.id, minimalUser);
|
||||
debugPrint(
|
||||
'Utilisateur minimal créé pour pré-remplissage du username avec rôle: $lastRole');
|
||||
debugPrint('Utilisateur minimal créé pour pré-remplissage du username avec rôle: $lastRole');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du vidage de la boîte users: $e');
|
||||
@@ -1266,8 +1211,7 @@ class UserRepository extends ChangeNotifier {
|
||||
await _chatConversationBox.clear();
|
||||
debugPrint('Boîte chat_conversations vidée');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors du vidage de la boîte chat_conversations: $e');
|
||||
debugPrint('Erreur lors du vidage de la boîte chat_conversations: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1319,15 +1263,15 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
try {
|
||||
// Vérifier si la boîte est ouverte avant de tenter de la fermer
|
||||
if (Hive.isBoxOpen(AppKeys.usersBoxName)) {
|
||||
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||
debugPrint('Fermeture de la boîte users...');
|
||||
try {
|
||||
await Hive.box<UserModel>(AppKeys.usersBoxName).close();
|
||||
await Hive.box<UserModel>(AppKeys.userBoxName).close();
|
||||
debugPrint('Boîte users fermée avec succès');
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la fermeture de la boîte users: $e');
|
||||
// Ne pas continuer avec la suppression si la fermeture a échoué
|
||||
throw e;
|
||||
rethrow;
|
||||
}
|
||||
|
||||
// Attendre un peu pour s'assurer que la fermeture est terminée
|
||||
@@ -1336,27 +1280,24 @@ class UserRepository extends ChangeNotifier {
|
||||
// Supprimer la boîte du disque seulement si la fermeture a réussi
|
||||
debugPrint('Suppression de la boîte users du disque...');
|
||||
try {
|
||||
await Hive.deleteBoxFromDisk(AppKeys.usersBoxName);
|
||||
await Hive.deleteBoxFromDisk(AppKeys.userBoxName);
|
||||
debugPrint('Boîte users supprimée du disque avec succès');
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la suppression de la boîte users: $e');
|
||||
// Ne pas continuer avec la réouverture si la suppression a échoué
|
||||
throw e;
|
||||
rethrow;
|
||||
}
|
||||
} else {
|
||||
debugPrint(
|
||||
'La boîte users est déjà fermée, tentative de suppression directe...');
|
||||
debugPrint('La boîte users est déjà fermée, tentative de suppression directe...');
|
||||
try {
|
||||
await Hive.deleteBoxFromDisk(AppKeys.usersBoxName);
|
||||
await Hive.deleteBoxFromDisk(AppKeys.userBoxName);
|
||||
debugPrint('Boîte users supprimée du disque avec succès');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors de la suppression directe de la boîte users: $e');
|
||||
debugPrint('Erreur lors de la suppression directe de la boîte users: $e');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors du processus de nettoyage de la boîte users: $e');
|
||||
debugPrint('Erreur lors du processus de nettoyage de la boîte users: $e');
|
||||
// Continuer malgré l'erreur, mais ne pas tenter de réouvrir la boîte
|
||||
return;
|
||||
}
|
||||
@@ -1366,12 +1307,11 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
// Rouvrir la boîte (elle sera vide)
|
||||
debugPrint('Réouverture de la boîte users (vide)...');
|
||||
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
|
||||
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
||||
|
||||
// Vérifier que la boîte est bien vide
|
||||
final checkUsers = _userBox.values.toList();
|
||||
debugPrint(
|
||||
'Après approche radicale: ${checkUsers.length} utilisateurs restants');
|
||||
debugPrint('Après approche radicale: ${checkUsers.length} utilisateurs restants');
|
||||
|
||||
// Forcer la réinitialisation du cache
|
||||
_cachedCurrentUser = null;
|
||||
@@ -1486,8 +1426,7 @@ class UserRepository extends ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
final unsyncedUsers =
|
||||
_userBox.values.where((user) => !user.isSynced).toList();
|
||||
final unsyncedUsers = _userBox.values.where((user) => !user.isSynced).toList();
|
||||
|
||||
if (unsyncedUsers.isEmpty) {
|
||||
return;
|
||||
@@ -1605,9 +1544,7 @@ class UserRepository extends ChangeNotifier {
|
||||
List<AmicaleModel> getAllClients() {
|
||||
try {
|
||||
_ensureBoxIsOpen(AppKeys.amicaleBoxName);
|
||||
return _amicaleBox.values
|
||||
.where((amicale) => amicale.fkType == 1)
|
||||
.toList();
|
||||
return _amicaleBox.values.where((amicale) => amicale.fkType == 1).toList();
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération des clients: $e');
|
||||
return [];
|
||||
@@ -1814,25 +1751,21 @@ class UserRepository extends ChangeNotifier {
|
||||
// Méthode pour traiter les données des associations utilisateurs-secteurs reçues de l'API
|
||||
Future<void> _processUserSectors(dynamic userSectorsData) async {
|
||||
try {
|
||||
debugPrint(
|
||||
'Traitement des données des associations utilisateurs-secteurs...');
|
||||
debugPrint('Traitement des données des associations utilisateurs-secteurs...');
|
||||
|
||||
// Vérifier que les données sont au bon format
|
||||
if (userSectorsData == null) {
|
||||
debugPrint(
|
||||
'Aucune donnée d\'association utilisateur-secteur à traiter');
|
||||
debugPrint('Aucune donnée d\'association utilisateur-secteur à traiter');
|
||||
return;
|
||||
}
|
||||
|
||||
List<dynamic> userSectorsList;
|
||||
if (userSectorsData is List) {
|
||||
userSectorsList = userSectorsData;
|
||||
} else if (userSectorsData is Map &&
|
||||
userSectorsData.containsKey('data')) {
|
||||
} else if (userSectorsData is Map && userSectorsData.containsKey('data')) {
|
||||
userSectorsList = userSectorsData['data'] as List<dynamic>;
|
||||
} else {
|
||||
debugPrint(
|
||||
'Format de données d\'associations utilisateurs-secteurs non reconnu');
|
||||
debugPrint('Format de données d\'associations utilisateurs-secteurs non reconnu');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1844,26 +1777,21 @@ class UserRepository extends ChangeNotifier {
|
||||
for (final userSectorData in userSectorsList) {
|
||||
try {
|
||||
final userSector = UserSectorModel.fromJson(userSectorData);
|
||||
await _userSectorBox.put(
|
||||
'${userSector.id}_${userSector.fkSector}', userSector);
|
||||
await _userSectorBox.put('${userSector.id}_${userSector.fkSector}', userSector);
|
||||
count++;
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors du traitement d\'une association utilisateur-secteur: $e');
|
||||
debugPrint('Erreur lors du traitement d\'une association utilisateur-secteur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
'$count associations utilisateurs-secteurs traitées et stockées');
|
||||
debugPrint('$count associations utilisateurs-secteurs traitées et stockées');
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'Erreur lors du traitement des associations utilisateurs-secteurs: $e');
|
||||
debugPrint('Erreur lors du traitement des associations utilisateurs-secteurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour traiter les données utilisateur reçues de l'API
|
||||
UserModel _processUserData(
|
||||
Map<String, dynamic> userData, String? sessionId, String? sessionExpiry) {
|
||||
UserModel _processUserData(Map<String, dynamic> userData, String? sessionId, String? sessionExpiry) {
|
||||
debugPrint('Traitement des données utilisateur: ${userData.toString()}');
|
||||
|
||||
// Convertir l'ID en int, qu'il soit déjà int ou string
|
||||
@@ -1884,20 +1812,15 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
// Convertir fk_entite en int si présent
|
||||
final dynamic rawFkEntite = userData['fk_entite'];
|
||||
final int? fkEntite = rawFkEntite != null
|
||||
? (rawFkEntite is String ? int.parse(rawFkEntite) : rawFkEntite as int)
|
||||
: null;
|
||||
final int? fkEntite = rawFkEntite != null ? (rawFkEntite is String ? int.parse(rawFkEntite) : rawFkEntite as int) : null;
|
||||
|
||||
// Convertir fk_titre en int si présent
|
||||
final dynamic rawFkTitre = userData['fk_titre'];
|
||||
final int? fkTitre = rawFkTitre != null
|
||||
? (rawFkTitre is String ? int.parse(rawFkTitre) : rawFkTitre as int)
|
||||
: null;
|
||||
final int? fkTitre = rawFkTitre != null ? (rawFkTitre is String ? int.parse(rawFkTitre) : rawFkTitre as int) : null;
|
||||
|
||||
// Traiter les dates si présentes
|
||||
DateTime? dateNaissance;
|
||||
if (userData['date_naissance'] != null &&
|
||||
userData['date_naissance'] != '') {
|
||||
if (userData['date_naissance'] != null && userData['date_naissance'] != '') {
|
||||
try {
|
||||
dateNaissance = DateTime.parse(userData['date_naissance']);
|
||||
} catch (e) {
|
||||
@@ -1929,8 +1852,7 @@ class UserRepository extends ChangeNotifier {
|
||||
isActive: true,
|
||||
isSynced: true,
|
||||
sessionId: sessionId,
|
||||
sessionExpiry:
|
||||
sessionExpiry != null ? DateTime.parse(sessionExpiry) : null,
|
||||
sessionExpiry: sessionExpiry != null ? DateTime.parse(sessionExpiry) : null,
|
||||
sectName: userData['sect_name'],
|
||||
fkEntite: fkEntite,
|
||||
fkTitre: fkTitre,
|
||||
|
||||
@@ -9,6 +9,295 @@ import 'package:retry/retry.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
class ApiService {
|
||||
static ApiService? _instance;
|
||||
static final Object _lock = Object();
|
||||
|
||||
// Propriétés existantes conservées
|
||||
final Dio _dio = Dio();
|
||||
late final String _baseUrl;
|
||||
late final String _appIdentifier;
|
||||
String? _sessionId;
|
||||
|
||||
// Singleton thread-safe
|
||||
static ApiService get instance {
|
||||
if (_instance == null) {
|
||||
throw Exception('ApiService non initialisé. Appelez initialize() d\'abord.');
|
||||
}
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
static Future<void> initialize() async {
|
||||
if (_instance == null) {
|
||||
synchronized(_lock, () {
|
||||
if (_instance == null) {
|
||||
_instance = ApiService._internal();
|
||||
debugPrint('✅ ApiService singleton initialisé');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Constructeur privé avec toute la logique existante
|
||||
ApiService._internal() {
|
||||
_configureEnvironment();
|
||||
|
||||
_dio.options.baseUrl = _baseUrl;
|
||||
_dio.options.connectTimeout = AppKeys.connectionTimeout;
|
||||
_dio.options.receiveTimeout = AppKeys.receiveTimeout;
|
||||
|
||||
final headers = Map<String, String>.from(AppKeys.defaultHeaders);
|
||||
headers['X-App-Identifier'] = _appIdentifier;
|
||||
_dio.options.headers.addAll(headers);
|
||||
|
||||
_dio.interceptors.add(InterceptorsWrapper(
|
||||
onRequest: (options, handler) {
|
||||
if (_sessionId != null) {
|
||||
options.headers[AppKeys.sessionHeader] = 'Bearer $_sessionId';
|
||||
}
|
||||
handler.next(options);
|
||||
},
|
||||
onError: (DioException error, handler) {
|
||||
if (error.response?.statusCode == 401) {
|
||||
_sessionId = null;
|
||||
}
|
||||
handler.next(error);
|
||||
},
|
||||
));
|
||||
|
||||
debugPrint('🔗 ApiService configuré pour $_baseUrl');
|
||||
}
|
||||
|
||||
// Fonction synchronized simple pour éviter les imports supplémentaires
|
||||
static T synchronized<T>(Object lock, T Function() computation) {
|
||||
return computation();
|
||||
}
|
||||
|
||||
// === TOUTES LES MÉTHODES EXISTANTES RESTENT IDENTIQUES ===
|
||||
|
||||
// Détermine l'environnement actuel (DEV, REC, PROD) en fonction de l'URL
|
||||
String _determineEnvironment() {
|
||||
if (!kIsWeb) {
|
||||
// En mode non-web, utiliser l'environnement de développement par défaut
|
||||
return 'DEV';
|
||||
}
|
||||
|
||||
final currentUrl = html.window.location.href.toLowerCase();
|
||||
|
||||
if (currentUrl.contains('dapp.geosector.fr')) {
|
||||
return 'DEV';
|
||||
} else if (currentUrl.contains('rapp.geosector.fr')) {
|
||||
return 'REC';
|
||||
} else {
|
||||
return 'PROD';
|
||||
}
|
||||
}
|
||||
|
||||
// Configure l'URL de base API et l'identifiant d'application selon l'environnement
|
||||
void _configureEnvironment() {
|
||||
final env = _determineEnvironment();
|
||||
|
||||
switch (env) {
|
||||
case 'DEV':
|
||||
_baseUrl = AppKeys.baseApiUrlDev;
|
||||
_appIdentifier = AppKeys.appIdentifierDev;
|
||||
break;
|
||||
case 'REC':
|
||||
_baseUrl = AppKeys.baseApiUrlRec;
|
||||
_appIdentifier = AppKeys.appIdentifierRec;
|
||||
break;
|
||||
default: // PROD
|
||||
_baseUrl = AppKeys.baseApiUrlProd;
|
||||
_appIdentifier = AppKeys.appIdentifierProd;
|
||||
}
|
||||
|
||||
debugPrint('GEOSECTOR 🔗 Environnement: $env, API: $_baseUrl');
|
||||
}
|
||||
|
||||
// Définir l'ID de session
|
||||
void setSessionId(String? sessionId) {
|
||||
_sessionId = sessionId;
|
||||
}
|
||||
|
||||
// Obtenir l'environnement actuel (utile pour le débogage)
|
||||
String getCurrentEnvironment() {
|
||||
return _determineEnvironment();
|
||||
}
|
||||
|
||||
// Obtenir l'URL API actuelle (utile pour le débogage)
|
||||
String getCurrentApiUrl() {
|
||||
return _baseUrl;
|
||||
}
|
||||
|
||||
// Obtenir l'identifiant d'application actuel (utile pour le débogage)
|
||||
String getCurrentAppIdentifier() {
|
||||
return _appIdentifier;
|
||||
}
|
||||
|
||||
// Vérifier la connectivité réseau
|
||||
Future<bool> hasInternetConnection() async {
|
||||
final connectivityResult = await (Connectivity().checkConnectivity());
|
||||
return connectivityResult != ConnectivityResult.none;
|
||||
}
|
||||
|
||||
// Méthode POST générique
|
||||
Future<Response> post(String path, {dynamic data}) async {
|
||||
try {
|
||||
return await _dio.post(path, data: data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode GET générique
|
||||
Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {
|
||||
try {
|
||||
return await _dio.get(path, queryParameters: queryParameters);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode PUT générique
|
||||
Future<Response> put(String path, {dynamic data}) async {
|
||||
try {
|
||||
return await _dio.put(path, data: data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode DELETE générique
|
||||
Future<Response> delete(String path) async {
|
||||
try {
|
||||
return await _dio.delete(path);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Authentification avec PHP session
|
||||
Future<Map<String, dynamic>> login(String username, String password, {required String type}) async {
|
||||
try {
|
||||
final response = await _dio.post(AppKeys.loginEndpoint, data: {
|
||||
'username': username,
|
||||
'password': password,
|
||||
'type': type, // Ajouter le type de connexion (user ou admin)
|
||||
});
|
||||
|
||||
// Vérifier la structure de la réponse
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
final status = data['status'] as String?;
|
||||
|
||||
// Afficher le message en cas d'erreur
|
||||
if (status != 'success') {
|
||||
final message = data['message'] as String?;
|
||||
debugPrint('Erreur d\'authentification: $message');
|
||||
}
|
||||
|
||||
// Si le statut est 'success', récupérer le session_id
|
||||
if (status == 'success' && data.containsKey('session_id')) {
|
||||
final sessionId = data['session_id'];
|
||||
// Définir la session pour les futures requêtes
|
||||
if (sessionId != null) {
|
||||
setSessionId(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Déconnexion
|
||||
Future<void> logout() async {
|
||||
try {
|
||||
if (_sessionId != null) {
|
||||
await _dio.post(AppKeys.logoutEndpoint);
|
||||
_sessionId = null;
|
||||
}
|
||||
} catch (e) {
|
||||
// Même en cas d'erreur, on réinitialise la session
|
||||
_sessionId = null;
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Utilisateurs
|
||||
Future<List<UserModel>> getUsers() async {
|
||||
try {
|
||||
final response = await retry(
|
||||
() => _dio.get('/users'),
|
||||
retryIf: (e) => e is SocketException || e is TimeoutException,
|
||||
);
|
||||
|
||||
return (response.data as List).map((json) => UserModel.fromJson(json)).toList();
|
||||
} catch (e) {
|
||||
// Gérer les erreurs
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<UserModel> getUserById(int id) async {
|
||||
try {
|
||||
final response = await _dio.get('/users/$id');
|
||||
return UserModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<UserModel> createUser(UserModel user) async {
|
||||
try {
|
||||
final response = await _dio.post('/users', data: user.toJson());
|
||||
return UserModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<UserModel> updateUser(UserModel user) async {
|
||||
try {
|
||||
final response = await _dio.put('/users/${user.id}', data: user.toJson());
|
||||
return UserModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteUser(String id) async {
|
||||
try {
|
||||
await _dio.delete('/users/$id');
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Espace réservé pour les futures méthodes de gestion des profils
|
||||
|
||||
// Espace réservé pour les futures méthodes de gestion des données
|
||||
|
||||
// Synchronisation en batch
|
||||
Future<Map<String, dynamic>> syncData({
|
||||
List<UserModel>? users,
|
||||
}) async {
|
||||
try {
|
||||
final Map<String, dynamic> payload = {
|
||||
if (users != null) 'users': users.map((u) => u.toJson()).toList(),
|
||||
};
|
||||
|
||||
final response = await _dio.post('/sync', data: payload);
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode de nettoyage pour les tests
|
||||
static void reset() {
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
final Dio _dio = Dio();
|
||||
late final String _baseUrl;
|
||||
late final String _appIdentifier;
|
||||
|
||||
144
app/lib/core/services/current_amicale_service.dart
Normal file
144
app/lib/core/services/current_amicale_service.dart
Normal file
@@ -0,0 +1,144 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||
import 'package:geosector_app/core/services/current_user_service.dart';
|
||||
|
||||
class CurrentAmicaleService extends ChangeNotifier {
|
||||
static CurrentAmicaleService? _instance;
|
||||
static CurrentAmicaleService get instance => _instance ??= CurrentAmicaleService._internal();
|
||||
CurrentAmicaleService._internal();
|
||||
|
||||
AmicaleModel? _currentAmicale;
|
||||
|
||||
// === GETTERS ===
|
||||
AmicaleModel? get currentAmicale => _currentAmicale;
|
||||
bool get hasAmicale => _currentAmicale != null;
|
||||
int? get amicaleId => _currentAmicale?.id;
|
||||
String? get amicaleName => _currentAmicale?.name;
|
||||
String? get amicaleEmail => _currentAmicale?.email;
|
||||
String? get amicalePhone => _currentAmicale?.phone;
|
||||
String? get amicaleMobile => _currentAmicale?.mobile;
|
||||
String? get amicaleAddress => _currentAmicale != null
|
||||
? '${_currentAmicale!.adresse1} ${_currentAmicale!.adresse2}'.trim()
|
||||
: null;
|
||||
String? get amicaleFullAddress => _currentAmicale != null
|
||||
? '${amicaleAddress ?? ''} ${_currentAmicale!.codePostal} ${_currentAmicale!.ville}'.trim()
|
||||
: null;
|
||||
bool get amicaleIsActive => _currentAmicale?.chkActive ?? false;
|
||||
bool get isClient => _currentAmicale?.fkType == 1;
|
||||
|
||||
// Géolocalisation
|
||||
bool get hasGpsCoordinates =>
|
||||
_currentAmicale?.gpsLat.isNotEmpty == true &&
|
||||
_currentAmicale?.gpsLng.isNotEmpty == true;
|
||||
|
||||
double? get latitude => hasGpsCoordinates
|
||||
? double.tryParse(_currentAmicale!.gpsLat)
|
||||
: null;
|
||||
|
||||
double? get longitude => hasGpsCoordinates
|
||||
? double.tryParse(_currentAmicale!.gpsLng)
|
||||
: null;
|
||||
|
||||
// === SETTERS ===
|
||||
Future<void> setAmicale(AmicaleModel? amicale) async {
|
||||
_currentAmicale = amicale;
|
||||
await _saveToHive();
|
||||
notifyListeners();
|
||||
debugPrint('🏢 Amicale définie: ${amicale?.name ?? 'null'}');
|
||||
}
|
||||
|
||||
Future<void> updateAmicale(AmicaleModel updatedAmicale) async {
|
||||
_currentAmicale = updatedAmicale;
|
||||
await _saveToHive();
|
||||
notifyListeners();
|
||||
debugPrint('🏢 Amicale mise à jour: ${updatedAmicale.name}');
|
||||
}
|
||||
|
||||
Future<void> clearAmicale() async {
|
||||
final amicaleName = _currentAmicale?.name;
|
||||
_currentAmicale = null;
|
||||
await _clearFromHive();
|
||||
notifyListeners();
|
||||
debugPrint('🏢 Amicale effacée: $amicaleName');
|
||||
}
|
||||
|
||||
// === AUTO-LOAD BASÉ SUR L'UTILISATEUR ===
|
||||
Future<void> loadUserAmicale() async {
|
||||
final user = CurrentUserService.instance.currentUser;
|
||||
if (user?.fkEntite != null) {
|
||||
await loadAmicaleById(user!.fkEntite!);
|
||||
} else {
|
||||
await clearAmicale();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadAmicaleById(int amicaleId) async {
|
||||
try {
|
||||
final box = Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||
final amicale = box.get('current_amicale');
|
||||
|
||||
if (amicale?.id == amicaleId) {
|
||||
_currentAmicale = amicale;
|
||||
debugPrint('📥 Amicale chargée depuis Hive: ${amicale?.name}');
|
||||
} else {
|
||||
// Si l'amicale n'est pas la bonne, la chercher ou l'effacer
|
||||
_currentAmicale = null;
|
||||
debugPrint('⚠️ Amicale ${amicaleId} non trouvée dans Hive');
|
||||
}
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur chargement amicale depuis Hive: $e');
|
||||
_currentAmicale = null;
|
||||
}
|
||||
}
|
||||
|
||||
// === PERSISTENCE HIVE ===
|
||||
Future<void> _saveToHive() async {
|
||||
try {
|
||||
if (_currentAmicale != null) {
|
||||
final box = Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||
await box.clear();
|
||||
await box.put('current_amicale', _currentAmicale!);
|
||||
debugPrint('💾 Amicale sauvegardée dans Hive');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur sauvegarde amicale Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _clearFromHive() async {
|
||||
try {
|
||||
final box = Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||
await box.clear();
|
||||
debugPrint('🗑️ Box amicale effacée');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur effacement amicale Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadFromHive() async {
|
||||
try {
|
||||
final box = Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||
_currentAmicale = box.get('current_amicale');
|
||||
|
||||
if (_currentAmicale != null) {
|
||||
debugPrint('📥 Amicale chargée depuis Hive: ${_currentAmicale!.name}');
|
||||
} else {
|
||||
debugPrint('ℹ️ Aucune amicale trouvée dans Hive');
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur chargement amicale depuis Hive: $e');
|
||||
_currentAmicale = null;
|
||||
}
|
||||
}
|
||||
|
||||
// === RESET POUR TESTS ===
|
||||
static void reset() {
|
||||
_instance?._currentAmicale = null;
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
156
app/lib/core/services/current_user_service.dart
Normal file
156
app/lib/core/services/current_user_service.dart
Normal file
@@ -0,0 +1,156 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
import 'package:geosector_app/core/data/models/user_model.dart';
|
||||
import 'package:geosector_app/core/services/current_amicale_service.dart';
|
||||
|
||||
class CurrentUserService extends ChangeNotifier {
|
||||
static CurrentUserService? _instance;
|
||||
static CurrentUserService get instance => _instance ??= CurrentUserService._internal();
|
||||
|
||||
CurrentUserService._internal();
|
||||
|
||||
UserModel? _currentUser;
|
||||
|
||||
// === GETTERS ===
|
||||
UserModel? get currentUser => _currentUser;
|
||||
bool get isLoggedIn => _currentUser?.hasValidSession ?? false;
|
||||
int get userRole => _currentUser?.role ?? 0;
|
||||
int? get userId => _currentUser?.id;
|
||||
String? get userEmail => _currentUser?.email;
|
||||
String? get userName => _currentUser?.name;
|
||||
String? get userFirstName => _currentUser?.firstName;
|
||||
String? get sessionId => _currentUser?.sessionId;
|
||||
int? get fkEntite => _currentUser?.fkEntite;
|
||||
String? get userPhone => _currentUser?.phone;
|
||||
String? get userMobile => _currentUser?.mobile;
|
||||
|
||||
// Vérifications de rôles
|
||||
bool get isUser => userRole == 1;
|
||||
bool get isAdminAmicale => userRole == 2;
|
||||
bool get isSuperAdmin => userRole >= 3;
|
||||
bool get canAccessAdmin => isAdminAmicale || isSuperAdmin;
|
||||
|
||||
// === SETTERS ===
|
||||
Future<void> setUser(UserModel? user) async {
|
||||
_currentUser = user;
|
||||
await _saveToHive();
|
||||
notifyListeners();
|
||||
|
||||
debugPrint('👤 Utilisateur défini: ${user?.email ?? 'null'}');
|
||||
|
||||
// Auto-synchroniser l'amicale si l'utilisateur a une entité
|
||||
if (user?.fkEntite != null) {
|
||||
await CurrentAmicaleService.instance.loadUserAmicale();
|
||||
} else {
|
||||
await CurrentAmicaleService.instance.clearAmicale();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateUser(UserModel updatedUser) async {
|
||||
_currentUser = updatedUser;
|
||||
await _saveToHive();
|
||||
notifyListeners();
|
||||
debugPrint('👤 Utilisateur mis à jour: ${updatedUser.email}');
|
||||
}
|
||||
|
||||
Future<void> clearUser() async {
|
||||
final userEmail = _currentUser?.email;
|
||||
_currentUser = null;
|
||||
await _clearFromHive();
|
||||
notifyListeners();
|
||||
debugPrint('👤 Utilisateur effacé: $userEmail');
|
||||
}
|
||||
|
||||
// === PERSISTENCE HIVE (nouvelle Box user) ===
|
||||
Future<void> _saveToHive() async {
|
||||
try {
|
||||
if (_currentUser != null) {
|
||||
final box = Hive.box<UserModel>(AppKeys.userBoxName); // Nouvelle Box
|
||||
await box.clear();
|
||||
await box.put('current_user', _currentUser!);
|
||||
debugPrint('💾 Utilisateur sauvegardé dans Box user');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur sauvegarde utilisateur Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _clearFromHive() async {
|
||||
try {
|
||||
final box = Hive.box<UserModel>(AppKeys.userBoxName); // Nouvelle Box
|
||||
await box.clear();
|
||||
debugPrint('🗑️ Box user effacée');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur effacement utilisateur Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadFromHive() async {
|
||||
try {
|
||||
final box = Hive.box<UserModel>(AppKeys.userBoxName); // Nouvelle Box
|
||||
final user = box.get('current_user');
|
||||
|
||||
if (user?.hasValidSession == true) {
|
||||
_currentUser = user;
|
||||
debugPrint('📥 Utilisateur chargé depuis Hive: ${user?.email}');
|
||||
} else {
|
||||
_currentUser = null;
|
||||
debugPrint('ℹ️ Aucun utilisateur valide trouvé dans Hive');
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur chargement utilisateur depuis Hive: $e');
|
||||
_currentUser = null;
|
||||
}
|
||||
}
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
Future<void> updateLastPath(String path) async {
|
||||
if (_currentUser != null) {
|
||||
await updateUser(_currentUser!.copyWith(lastPath: path));
|
||||
}
|
||||
}
|
||||
|
||||
String? getLastPath() => _currentUser?.lastPath;
|
||||
|
||||
String getDefaultRoute() {
|
||||
if (!isLoggedIn) return '/';
|
||||
return canAccessAdmin ? '/admin' : '/user';
|
||||
}
|
||||
|
||||
String getRoleLabel() {
|
||||
switch (userRole) {
|
||||
case 1:
|
||||
return 'Utilisateur';
|
||||
case 2:
|
||||
return 'Admin Amicale';
|
||||
case 3:
|
||||
return 'Super Admin';
|
||||
default:
|
||||
return 'Inconnu';
|
||||
}
|
||||
}
|
||||
|
||||
bool hasPermission(String permission) {
|
||||
switch (permission) {
|
||||
case 'admin':
|
||||
return canAccessAdmin;
|
||||
case 'super_admin':
|
||||
return isSuperAdmin;
|
||||
case 'manage_amicale':
|
||||
return canAccessAdmin;
|
||||
case 'manage_users':
|
||||
return isSuperAdmin;
|
||||
default:
|
||||
return isLoggedIn;
|
||||
}
|
||||
}
|
||||
|
||||
// === RESET POUR TESTS ===
|
||||
static void reset() {
|
||||
_instance?._currentUser = null;
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,7 @@ class HiveResetService {
|
||||
/// Réinitialise complètement Hive et recrée les boîtes nécessaires
|
||||
static Future<bool> resetAndRecreateHiveBoxes() async {
|
||||
try {
|
||||
debugPrint(
|
||||
'HiveResetService: Début de la réinitialisation complète de Hive');
|
||||
debugPrint('HiveResetService: Début de la réinitialisation complète de Hive');
|
||||
|
||||
// Approche plus radicale pour le web : supprimer directement IndexedDB
|
||||
if (kIsWeb) {
|
||||
@@ -68,8 +67,7 @@ class HiveResetService {
|
||||
// Rouvrir les boîtes essentielles
|
||||
await _reopenEssentialBoxes();
|
||||
|
||||
debugPrint(
|
||||
'HiveResetService: Réinitialisation complète terminée avec succès');
|
||||
debugPrint('HiveResetService: Réinitialisation complète terminée avec succès');
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('HiveResetService: Erreur lors de la réinitialisation: $e');
|
||||
@@ -80,7 +78,7 @@ class HiveResetService {
|
||||
/// Ferme toutes les boîtes Hive ouvertes
|
||||
static Future<void> _closeAllBoxes() async {
|
||||
final boxNames = [
|
||||
AppKeys.usersBoxName,
|
||||
AppKeys.userBoxName,
|
||||
AppKeys.amicaleBoxName,
|
||||
AppKeys.clientsBoxName,
|
||||
AppKeys.operationsBoxName,
|
||||
@@ -137,7 +135,7 @@ class HiveResetService {
|
||||
debugPrint('HiveResetService: Réouverture des boîtes essentielles');
|
||||
|
||||
// Ouvrir les boîtes essentielles au démarrage
|
||||
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
|
||||
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
||||
await Hive.openBox<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||
await Hive.openBox<ClientModel>(AppKeys.clientsBoxName);
|
||||
await Hive.openBox(AppKeys.settingsBoxName);
|
||||
|
||||
@@ -12,8 +12,7 @@ class HiveWebFix {
|
||||
if (!kIsWeb) return;
|
||||
|
||||
try {
|
||||
debugPrint(
|
||||
'HiveWebFix: Nettoyage sécurisé des boîtes Hive en version web');
|
||||
debugPrint('HiveWebFix: Nettoyage sécurisé des boîtes Hive en version web');
|
||||
|
||||
// Liste des boîtes à nettoyer
|
||||
final boxesToClean = [
|
||||
@@ -36,16 +35,14 @@ class HiveWebFix {
|
||||
await box.clear();
|
||||
debugPrint('HiveWebFix: Boîte $boxName nettoyée avec succès');
|
||||
} else {
|
||||
debugPrint(
|
||||
'HiveWebFix: La boîte $boxName n\'est pas ouverte, ouverture temporaire');
|
||||
debugPrint('HiveWebFix: La boîte $boxName n\'est pas ouverte, ouverture temporaire');
|
||||
final box = await Hive.openBox(boxName);
|
||||
await box.clear();
|
||||
await box.close();
|
||||
debugPrint('HiveWebFix: Boîte $boxName nettoyée et fermée');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(
|
||||
'HiveWebFix: Erreur lors du nettoyage de la boîte $boxName: $e');
|
||||
debugPrint('HiveWebFix: Erreur lors du nettoyage de la boîte $boxName: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,14 +62,13 @@ class HiveWebFix {
|
||||
// Vérifier si IndexedDB est accessible
|
||||
final isIndexedDBAvailable = js.context.hasProperty('indexedDB');
|
||||
if (!isIndexedDBAvailable) {
|
||||
debugPrint(
|
||||
'HiveWebFix: IndexedDB n\'est pas disponible dans ce navigateur');
|
||||
debugPrint('HiveWebFix: IndexedDB n\'est pas disponible dans ce navigateur');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Liste des boîtes essentielles
|
||||
final essentialBoxes = [
|
||||
AppKeys.usersBoxName,
|
||||
AppKeys.userBoxName,
|
||||
AppKeys.settingsBoxName,
|
||||
];
|
||||
|
||||
@@ -80,8 +76,7 @@ class HiveWebFix {
|
||||
for (final boxName in essentialBoxes) {
|
||||
try {
|
||||
if (!Hive.isBoxOpen(boxName)) {
|
||||
debugPrint(
|
||||
'HiveWebFix: Ouverture de la boîte essentielle $boxName');
|
||||
debugPrint('HiveWebFix: Ouverture de la boîte essentielle $boxName');
|
||||
await Hive.openBox(boxName);
|
||||
}
|
||||
|
||||
@@ -89,15 +84,13 @@ class HiveWebFix {
|
||||
final box = Hive.box(boxName);
|
||||
// Tenter une opération simple pour vérifier l'intégrité
|
||||
final length = box.length;
|
||||
debugPrint(
|
||||
'HiveWebFix: Boîte $boxName accessible avec $length éléments');
|
||||
debugPrint('HiveWebFix: Boîte $boxName accessible avec $length éléments');
|
||||
} catch (e) {
|
||||
debugPrint('HiveWebFix: Erreur d\'accès à la boîte $boxName: $e');
|
||||
|
||||
// Tenter de réparer en réinitialisant Hive
|
||||
try {
|
||||
debugPrint(
|
||||
'HiveWebFix: Tentative de réparation de la boîte $boxName');
|
||||
debugPrint('HiveWebFix: Tentative de réparation de la boîte $boxName');
|
||||
// Fermer la boîte si elle est ouverte
|
||||
if (Hive.isBoxOpen(boxName)) {
|
||||
await Hive.box(boxName).close();
|
||||
@@ -107,8 +100,7 @@ class HiveWebFix {
|
||||
await Hive.openBox(boxName);
|
||||
debugPrint('HiveWebFix: Boîte $boxName réparée avec succès');
|
||||
} catch (repairError) {
|
||||
debugPrint(
|
||||
'HiveWebFix: Échec de la réparation de la boîte $boxName: $repairError');
|
||||
debugPrint('HiveWebFix: Échec de la réparation de la boîte $boxName: $repairError');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -132,7 +124,7 @@ class HiveWebFix {
|
||||
|
||||
// Fermer toutes les boîtes ouvertes
|
||||
final boxesToClose = [
|
||||
AppKeys.usersBoxName,
|
||||
AppKeys.userBoxName,
|
||||
AppKeys.operationsBoxName,
|
||||
AppKeys.sectorsBoxName,
|
||||
AppKeys.passagesBoxName,
|
||||
|
||||
@@ -133,7 +133,110 @@ void _registerHiveAdapters() {
|
||||
/// Ouvre les boîtes Hive essentielles
|
||||
Future<void> _openEssentialHiveBoxes() async {
|
||||
final boxesToOpen = [
|
||||
{'name': AppKeys.usersBoxName, 'type': 'UserModel'},
|
||||
{'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;
|
||||
}
|
||||
}
|
||||
final boxesToOpen = [
|
||||
{'name': AppKeys.userBoxName, 'type': 'UserModel'},
|
||||
{'name': AppKeys.amicaleBoxName, 'type': 'AmicaleModel'},
|
||||
{'name': AppKeys.clientsBoxName, 'type': 'ClientModel'},
|
||||
{'name': AppKeys.settingsBoxName, 'type': 'dynamic'},
|
||||
|
||||
@@ -49,8 +49,7 @@ class DotsPainter extends CustomPainter {
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
|
||||
class _SplashPageState extends State<SplashPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
late Animation<double> _scaleAnimation;
|
||||
bool _isInitializing = true;
|
||||
@@ -72,9 +71,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
// Fallback sur la version du AppInfoService si elle existe
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_appVersion = AppInfoService.fullVersion
|
||||
.split(' ')
|
||||
.last; // Extraire juste le numéro
|
||||
_appVersion = AppInfoService.fullVersion.split(' ').last; // Extraire juste le numéro
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -154,30 +151,18 @@ class _SplashPageState extends State<SplashPage>
|
||||
|
||||
// Structure pour les boîtes à ouvrir avec leurs noms d'affichage
|
||||
final boxesToOpen = [
|
||||
{'name': AppKeys.usersBoxName, 'display': 'Préparation utilisateurs'},
|
||||
{'name': AppKeys.userBoxName, 'display': 'Préparation utilisateurs'},
|
||||
{'name': AppKeys.amicaleBoxName, 'display': 'Préparation amicale'},
|
||||
{'name': AppKeys.clientsBoxName, 'display': 'Préparation clients'},
|
||||
{'name': AppKeys.regionsBoxName, 'display': 'Préparation régions'},
|
||||
{
|
||||
'name': AppKeys.operationsBoxName,
|
||||
'display': 'Préparation opérations'
|
||||
},
|
||||
{'name': AppKeys.operationsBoxName, 'display': 'Préparation opérations'},
|
||||
{'name': AppKeys.sectorsBoxName, 'display': 'Préparation secteurs'},
|
||||
{'name': AppKeys.passagesBoxName, 'display': 'Préparation passages'},
|
||||
{'name': AppKeys.membresBoxName, 'display': 'Préparation membres'},
|
||||
{
|
||||
'name': AppKeys.userSectorBoxName,
|
||||
'display': 'Préparation secteurs utilisateurs'
|
||||
},
|
||||
{'name': AppKeys.userSectorBoxName, 'display': 'Préparation secteurs utilisateurs'},
|
||||
{'name': AppKeys.settingsBoxName, 'display': 'Préparation paramètres'},
|
||||
{
|
||||
'name': AppKeys.chatConversationsBoxName,
|
||||
'display': 'Préparation conversations'
|
||||
},
|
||||
{
|
||||
'name': AppKeys.chatMessagesBoxName,
|
||||
'display': 'Préparation messages'
|
||||
},
|
||||
{'name': AppKeys.chatConversationsBoxName, 'display': 'Préparation conversations'},
|
||||
{'name': AppKeys.chatMessagesBoxName, 'display': 'Préparation messages'},
|
||||
];
|
||||
|
||||
// Calculer l'incrément de progression pour chaque boîte (0.75 / nombre de boîtes)
|
||||
@@ -202,7 +187,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
debugPrint('Ouverture de la boîte $boxName ($displayName)...');
|
||||
|
||||
// Ouvrir la boîte avec le type approprié
|
||||
if (boxName == AppKeys.usersBoxName) {
|
||||
if (boxName == AppKeys.userBoxName) {
|
||||
await Hive.openBox<UserModel>(boxName);
|
||||
} else if (boxName == AppKeys.amicaleBoxName) {
|
||||
await Hive.openBox<AmicaleModel>(boxName);
|
||||
@@ -296,7 +281,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: DotsPainter(),
|
||||
child: Container(width: double.infinity, height: double.infinity),
|
||||
child: const SizedBox(width: double.infinity, height: double.infinity),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -351,8 +336,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
'Une application puissante et intuitive de gestion de vos distributions de calendriers',
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
color:
|
||||
theme.colorScheme.onBackground.withOpacity(0.7),
|
||||
color: theme.colorScheme.onSurface.withOpacity(0.7),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
@@ -380,8 +364,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
Text(
|
||||
_statusMessage,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color:
|
||||
theme.colorScheme.onBackground.withOpacity(0.7),
|
||||
color: theme.colorScheme.onSurface.withOpacity(0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -394,8 +377,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
context.go(
|
||||
'/login/user'); // Utiliser la route spécifique
|
||||
context.go('/login/user'); // Utiliser la route spécifique
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
@@ -426,8 +408,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
context.go(
|
||||
'/login/admin'); // Utiliser la route spécifique
|
||||
context.go('/login/admin'); // Utiliser la route spécifique
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
@@ -451,8 +432,7 @@ class _SplashPageState extends State<SplashPage>
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(
|
||||
height: 32), // 2 espaces sous le bouton précédent
|
||||
const SizedBox(height: 32), // 2 espaces sous le bouton précédent
|
||||
|
||||
// Bouton d'inscription
|
||||
AnimatedOpacity(
|
||||
|
||||
Reference in New Issue
Block a user