Release v3.1.4 - Mode terrain et génération PDF #10
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1775,7 +1775,6 @@ file:///Users/pierre/dev/geosector/app/lib/core/repositories/client_repository.d
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/membre_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/operation_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/passage_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/region_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/sector_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/user_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/services/api_service.dart
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1774,7 +1774,6 @@ file:///Users/pierre/dev/geosector/app/lib/core/repositories/client_repository.d
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/membre_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/operation_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/passage_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/region_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/sector_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/user_repository.dart
|
||||
file:///Users/pierre/dev/geosector/app/lib/core/services/api_service.dart
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -57,10 +57,10 @@ echo "$(date): Début refactorisation singletons" >> refactoring.log
|
||||
|
||||
**Actions** :
|
||||
|
||||
- [ ] Créer la branche `singletons`
|
||||
- [ ] Sauvegarder les fichiers critiques
|
||||
- [ ] Documenter le début de la refactorisation
|
||||
- [ ] Commit initial de la branche
|
||||
- [x] Créer la branche `singletons`
|
||||
- [x] Sauvegarder les fichiers critiques
|
||||
- [x] Documenter le début de la refactorisation
|
||||
- [x] Commit initial de la branche
|
||||
|
||||
```bash
|
||||
git add .
|
||||
@@ -87,21 +87,21 @@ grep -r "usersBoxName" app/lib --include="*.dart" > audit_usersbox.txt
|
||||
|
||||
**Actions** :
|
||||
|
||||
- [ ] Lister tous les fichiers utilisant ApiService
|
||||
- [ ] Identifier les patterns d'injection actuels
|
||||
- [ ] Noter les accès aux données utilisateur/amicale
|
||||
- [ ] Documenter les méthodes utilisées
|
||||
- [ ] Analyser les Box Hive users/amicale
|
||||
- [ ] Identifier toutes les occurrences de "usersBoxName"
|
||||
- [x] Lister tous les fichiers utilisant ApiService
|
||||
- [x] Identifier les patterns d'injection actuels
|
||||
- [x] Noter les accès aux données utilisateur/amicale
|
||||
- [x] Documenter les méthodes utilisées
|
||||
- [x] Analyser les Box Hive users/amicale
|
||||
- [x] Identifier toutes les occurrences de "usersBoxName"
|
||||
|
||||
#### Tâche 1.2: Modification app_keys.dart pour renommage Box (10 min)
|
||||
|
||||
**Fichier à modifier** : `app/lib/core/constants/app_keys.dart`
|
||||
**Actions** :
|
||||
|
||||
- [ ] Changer `usersBoxName` en `userBoxName`
|
||||
- [ ] Ajouter une constante de migration si nécessaire
|
||||
- [ ] Documenter le changement
|
||||
- [x] Changer `usersBoxName` en `userBoxName`
|
||||
- [x] Ajouter une constante de migration si nécessaire
|
||||
- [x] Documenter le changement
|
||||
|
||||
**Code à modifier** :
|
||||
|
||||
@@ -134,8 +134,8 @@ static const String usersBoxNameOld = 'users'; // Pour migration si nécessaire
|
||||
**Fichier à modifier** : `app/lib/main.dart`
|
||||
**Actions** :
|
||||
|
||||
- [ ] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [ ] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
||||
- [x] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [x] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
||||
- [ ] Ajouter logique de migration depuis l'ancienne Box si nécessaire
|
||||
|
||||
**Code à modifier** :
|
||||
@@ -180,9 +180,9 @@ Future<void> _openEssentialHiveBoxes() async {
|
||||
|
||||
**Actions** :
|
||||
|
||||
- [ ] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [ ] Modifier les getters de Box
|
||||
- [ ] Tester que la compilation passe
|
||||
- [x] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [x] Modifier les getters de Box
|
||||
- [x] Tester que la compilation passe
|
||||
|
||||
**Code à modifier** :
|
||||
|
||||
|
||||
0
app/audit_apiservice.txt
Normal file
0
app/audit_apiservice.txt
Normal file
0
app/audit_currentuser.txt
Normal file
0
app/audit_currentuser.txt
Normal file
0
app/audit_getcurrentuser.txt
Normal file
0
app/audit_getcurrentuser.txt
Normal file
0
app/audit_userrepository.txt
Normal file
0
app/audit_userrepository.txt
Normal file
0
app/audit_usersbox.txt
Normal file
0
app/audit_usersbox.txt
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"guid":"dc4b70c03e8043e50e38f2068887b1d4","name":"Pods","path":"/Users/pierre/dev/geosector/app/ios/Pods/Pods.xcodeproj/project.xcworkspace","projects":["PROJECT@v11_mod=0987d131841f12618fa22c05d7871702_hash=bfdfe7dc352907fc980b868725387e98plugins=1OJSG6M1FOV3XYQCBH7Z29RZ0FPR9XDE1"]}
|
||||
{"guid":"dc4b70c03e8043e50e38f2068887b1d4","name":"Pods","path":"/Users/pierre/dev/geosector/app/ios/Pods/Pods.xcodeproj/project.xcworkspace","projects":["PROJECT@v11_mod=9c247933552af22255bf791d596f2dce_hash=bfdfe7dc352907fc980b868725387e98plugins=1OJSG6M1FOV3XYQCBH7Z29RZ0FPR9XDE1"]}
|
||||
@@ -39,6 +39,6 @@ _flutter.buildConfig = {"engineRevision":"1425e5e9ec5eeb4f225c401d8db69b860e0fde
|
||||
|
||||
_flutter.loader.load({
|
||||
serviceWorkerSettings: {
|
||||
serviceWorkerVersion: "2020305023"
|
||||
serviceWorkerVersion: "3087561979"
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,13 +3,13 @@ const MANIFEST = 'flutter-app-manifest';
|
||||
const TEMP = 'flutter-temp-cache';
|
||||
const CACHE_NAME = 'flutter-app-cache';
|
||||
|
||||
const RESOURCES = {"flutter_bootstrap.js": "aac8cb24376ac6215b72a88087969ea7",
|
||||
const RESOURCES = {"flutter_bootstrap.js": "1dbbc20d0a6216228635de38eb5222a5",
|
||||
"version.json": "727f6f584c125faac83c6d2a4c96fb3d",
|
||||
"index.html": "2aab03d10fea3b608e3eddc0fc0077e5",
|
||||
"/": "2aab03d10fea3b608e3eddc0fc0077e5",
|
||||
"favicon-64.png": "259540a3217e969237530444ca0eaed3",
|
||||
"favicon-16.png": "106142fb24eba190e475dbe6513cc9ff",
|
||||
"main.dart.js": "00dc118c0abed215458c35d4ba5a89b1",
|
||||
"main.dart.js": "7530a148b4d52ca92f4706f660f16907",
|
||||
"flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
|
||||
"favicon.png": "21510778ead066ac826ad69302400773",
|
||||
"icons/Icon-192.png": "f36879dd176101fac324b68793e4683c",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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;
|
||||
|
||||
// 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;
|
||||
lastRole = lastUser.role;
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
'Username sauvegardé pour pré-remplissage: $lastUsername');
|
||||
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