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:
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/membre_repository.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/operation_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/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/sector_repository.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/user_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:///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/membre_repository.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/operation_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/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/sector_repository.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/repositories/user_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:///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** :
|
**Actions** :
|
||||||
|
|
||||||
- [ ] Créer la branche `singletons`
|
- [x] Créer la branche `singletons`
|
||||||
- [ ] Sauvegarder les fichiers critiques
|
- [x] Sauvegarder les fichiers critiques
|
||||||
- [ ] Documenter le début de la refactorisation
|
- [x] Documenter le début de la refactorisation
|
||||||
- [ ] Commit initial de la branche
|
- [x] Commit initial de la branche
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git add .
|
git add .
|
||||||
@@ -87,21 +87,21 @@ grep -r "usersBoxName" app/lib --include="*.dart" > audit_usersbox.txt
|
|||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
- [ ] Lister tous les fichiers utilisant ApiService
|
- [x] Lister tous les fichiers utilisant ApiService
|
||||||
- [ ] Identifier les patterns d'injection actuels
|
- [x] Identifier les patterns d'injection actuels
|
||||||
- [ ] Noter les accès aux données utilisateur/amicale
|
- [x] Noter les accès aux données utilisateur/amicale
|
||||||
- [ ] Documenter les méthodes utilisées
|
- [x] Documenter les méthodes utilisées
|
||||||
- [ ] Analyser les Box Hive users/amicale
|
- [x] Analyser les Box Hive users/amicale
|
||||||
- [ ] Identifier toutes les occurrences de "usersBoxName"
|
- [x] Identifier toutes les occurrences de "usersBoxName"
|
||||||
|
|
||||||
#### Tâche 1.2: Modification app_keys.dart pour renommage Box (10 min)
|
#### Tâche 1.2: Modification app_keys.dart pour renommage Box (10 min)
|
||||||
|
|
||||||
**Fichier à modifier** : `app/lib/core/constants/app_keys.dart`
|
**Fichier à modifier** : `app/lib/core/constants/app_keys.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
- [ ] Changer `usersBoxName` en `userBoxName`
|
- [x] Changer `usersBoxName` en `userBoxName`
|
||||||
- [ ] Ajouter une constante de migration si nécessaire
|
- [x] Ajouter une constante de migration si nécessaire
|
||||||
- [ ] Documenter le changement
|
- [x] Documenter le changement
|
||||||
|
|
||||||
**Code à modifier** :
|
**Code à modifier** :
|
||||||
|
|
||||||
@@ -134,8 +134,8 @@ static const String usersBoxNameOld = 'users'; // Pour migration si nécessaire
|
|||||||
**Fichier à modifier** : `app/lib/main.dart`
|
**Fichier à modifier** : `app/lib/main.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
- [ ] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
- [x] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||||
- [ ] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
- [x] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
||||||
- [ ] Ajouter logique de migration depuis l'ancienne Box si nécessaire
|
- [ ] Ajouter logique de migration depuis l'ancienne Box si nécessaire
|
||||||
|
|
||||||
**Code à modifier** :
|
**Code à modifier** :
|
||||||
@@ -180,9 +180,9 @@ Future<void> _openEssentialHiveBoxes() async {
|
|||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
- [ ] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
- [x] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||||
- [ ] Modifier les getters de Box
|
- [x] Modifier les getters de Box
|
||||||
- [ ] Tester que la compilation passe
|
- [x] Tester que la compilation passe
|
||||||
|
|
||||||
**Code à modifier** :
|
**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({
|
_flutter.loader.load({
|
||||||
serviceWorkerSettings: {
|
serviceWorkerSettings: {
|
||||||
serviceWorkerVersion: "2020305023"
|
serviceWorkerVersion: "3087561979"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ const MANIFEST = 'flutter-app-manifest';
|
|||||||
const TEMP = 'flutter-temp-cache';
|
const TEMP = 'flutter-temp-cache';
|
||||||
const CACHE_NAME = 'flutter-app-cache';
|
const CACHE_NAME = 'flutter-app-cache';
|
||||||
|
|
||||||
const RESOURCES = {"flutter_bootstrap.js": "aac8cb24376ac6215b72a88087969ea7",
|
const RESOURCES = {"flutter_bootstrap.js": "1dbbc20d0a6216228635de38eb5222a5",
|
||||||
"version.json": "727f6f584c125faac83c6d2a4c96fb3d",
|
"version.json": "727f6f584c125faac83c6d2a4c96fb3d",
|
||||||
"index.html": "2aab03d10fea3b608e3eddc0fc0077e5",
|
"index.html": "2aab03d10fea3b608e3eddc0fc0077e5",
|
||||||
"/": "2aab03d10fea3b608e3eddc0fc0077e5",
|
"/": "2aab03d10fea3b608e3eddc0fc0077e5",
|
||||||
"favicon-64.png": "259540a3217e969237530444ca0eaed3",
|
"favicon-64.png": "259540a3217e969237530444ca0eaed3",
|
||||||
"favicon-16.png": "106142fb24eba190e475dbe6513cc9ff",
|
"favicon-16.png": "106142fb24eba190e475dbe6513cc9ff",
|
||||||
"main.dart.js": "00dc118c0abed215458c35d4ba5a89b1",
|
"main.dart.js": "7530a148b4d52ca92f4706f660f16907",
|
||||||
"flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
|
"flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
|
||||||
"favicon.png": "21510778ead066ac826ad69302400773",
|
"favicon.png": "21510778ead066ac826ad69302400773",
|
||||||
"icons/Icon-192.png": "f36879dd176101fac324b68793e4683c",
|
"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
|
/// Fichier contenant toutes les constantes utilisées dans l'application
|
||||||
/// Centralise les clés, noms de boîtes Hive, et autres constantes
|
/// Centralise les clés, noms de boîtes Hive, et autres constantes
|
||||||
/// pour faciliter la maintenance et éviter les erreurs de frappe
|
/// pour faciliter la maintenance et éviter les erreurs de frappe
|
||||||
|
library;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AppKeys {
|
class AppKeys {
|
||||||
// Noms des boîtes Hive
|
// 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 amicaleBoxName = 'amicale';
|
||||||
static const String clientsBoxName = 'clients';
|
static const String clientsBoxName = 'clients';
|
||||||
static const String operationsBoxName = 'operations';
|
static const String operationsBoxName = 'operations';
|
||||||
@@ -49,12 +51,9 @@ class AppKeys {
|
|||||||
static const Duration sessionDefaultExpiry = Duration(days: 7);
|
static const Duration sessionDefaultExpiry = Duration(days: 7);
|
||||||
|
|
||||||
// Clés API externes
|
// Clés API externes
|
||||||
static const String mapboxApiKeyDev =
|
static const String mapboxApiKeyDev = 'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY21hanVmNjN5MTM5djJtczdsMW92cjQ0ciJ9.pUCMuvWPB3cuBaPh4ywTAw';
|
||||||
'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY21hanVmNjN5MTM5djJtczdsMW92cjQ0ciJ9.pUCMuvWPB3cuBaPh4ywTAw';
|
static const String mapboxApiKeyRec = 'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY21hanVlZ3FiMGx0NDJpc2k4YnkxaWZ2dSJ9.OqGJtjlWRgB4fIjECCB8WA';
|
||||||
static const String mapboxApiKeyRec =
|
static const String mapboxApiKeyProd = 'pk.eyJ1IjoicHZkNnNvZnQiLCJhIjoiY204dTNhNmd0MGV1ZzJqc2pnNnB0NjYxdSJ9.TA5Mvliyn91Oi01F_2Yuxw';
|
||||||
'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
|
// Méthode pour obtenir la clé API Mapbox en fonction de l'environnement actuel
|
||||||
static String getMapboxApiKey(String environment) {
|
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
|
// 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<UserModel> get _userBox => Hive.box<UserModel>(AppKeys.userBoxName);
|
||||||
Box<AmicaleModel> get _amicaleBox =>
|
Box<AmicaleModel> get _amicaleBox => Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||||
Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
|
||||||
|
|
||||||
// Getters pour les autres boîtes qui vérifient si elles sont ouvertes avant accès
|
// Getters pour les autres boîtes qui vérifient si elles sont ouvertes avant accès
|
||||||
Box<OperationModel> get _operationBox {
|
Box<OperationModel> get _operationBox {
|
||||||
@@ -118,10 +117,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
|
||||||
UserRepository(this._apiService,
|
UserRepository(this._apiService,
|
||||||
{SyncService? syncService,
|
{SyncService? syncService, OperationRepository? operationRepository, SectorRepository? sectorRepository, PassageRepository? passageRepository})
|
||||||
OperationRepository? operationRepository,
|
|
||||||
SectorRepository? sectorRepository,
|
|
||||||
PassageRepository? passageRepository})
|
|
||||||
: _syncService = syncService,
|
: _syncService = syncService,
|
||||||
_operationRepository = operationRepository,
|
_operationRepository = operationRepository,
|
||||||
_sectorRepository = sectorRepository,
|
_sectorRepository = sectorRepository,
|
||||||
@@ -160,7 +156,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
if (user.role is String) {
|
if (user.role is String) {
|
||||||
return int.tryParse(user.role as String) ?? 1;
|
return int.tryParse(user.role as String) ?? 1;
|
||||||
} else {
|
} else {
|
||||||
return user.role as int;
|
return user.role;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,15 +164,13 @@ class UserRepository extends ChangeNotifier {
|
|||||||
UserModel? _getCurrentUserFromStorage() {
|
UserModel? _getCurrentUserFromStorage() {
|
||||||
try {
|
try {
|
||||||
// Vérifier d'abord si la boîte est ouverte
|
// 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...');
|
debugPrint('Boîte users non ouverte, tentative d\'ouverture...');
|
||||||
return null; // Retourner null plutôt que d'essayer d'ouvrir ici
|
return null; // Retourner null plutôt que d'essayer d'ouvrir ici
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chercher un utilisateur avec une session active
|
// Chercher un utilisateur avec une session active
|
||||||
final activeUsers = _userBox.values
|
final activeUsers = _userBox.values.where((user) => user.sessionId != null && user.sessionId!.isNotEmpty).toList();
|
||||||
.where((user) => user.sessionId != null && user.sessionId!.isNotEmpty)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
// S'il y a des utilisateurs actifs, retourner le premier
|
// S'il y a des utilisateurs actifs, retourner le premier
|
||||||
if (activeUsers.isNotEmpty) {
|
if (activeUsers.isNotEmpty) {
|
||||||
@@ -185,8 +179,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors de la récupération de l\'utilisateur depuis le stockage: $e');
|
||||||
'Erreur lors de la récupération de l\'utilisateur depuis le stockage: $e');
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,8 +211,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login API PHP
|
// Login API PHP
|
||||||
Future<Map<String, dynamic>> loginAPI(String username, String password,
|
Future<Map<String, dynamic>> loginAPI(String username, String password, {required String type}) async {
|
||||||
{required String type}) async {
|
|
||||||
try {
|
try {
|
||||||
return await _apiService.login(username, password, type: type);
|
return await _apiService.login(username, password, type: type);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -229,19 +221,11 @@ class UserRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register API PHP - Uniquement pour les administrateurs
|
// Register API PHP - Uniquement pour les administrateurs
|
||||||
Future<Map<String, dynamic>> registerAPI(String email, String name,
|
Future<Map<String, dynamic>> registerAPI(String email, String name, String amicaleName, String postalCode, String cityName) async {
|
||||||
String amicaleName, String postalCode, String cityName) async {
|
|
||||||
try {
|
try {
|
||||||
final Map<String, dynamic> data = {
|
final Map<String, dynamic> data = {'email': email, 'name': name, 'amicale_name': amicaleName, 'postal_code': postalCode, 'city_name': cityName};
|
||||||
'email': email,
|
|
||||||
'name': name,
|
|
||||||
'amicale_name': amicaleName,
|
|
||||||
'postal_code': postalCode,
|
|
||||||
'city_name': cityName
|
|
||||||
};
|
|
||||||
|
|
||||||
final response =
|
final response = await _apiService.post(AppKeys.registerEndpoint, data: data);
|
||||||
await _apiService.post(AppKeys.registerEndpoint, data: data);
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur register API: $e');
|
debugPrint('Erreur register API: $e');
|
||||||
@@ -270,20 +254,16 @@ class UserRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Méthode d'inscription (uniquement pour les administrateurs)
|
// Méthode d'inscription (uniquement pour les administrateurs)
|
||||||
Future<bool> register(String email, String password, String name,
|
Future<bool> register(String email, String password, String name, String amicaleName, String postalCode, String cityName) async {
|
||||||
String amicaleName, String postalCode, String cityName) async {
|
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Enregistrer l'administrateur via l'API
|
// Enregistrer l'administrateur via l'API
|
||||||
final apiResult =
|
final apiResult = await registerAPI(email, name, amicaleName, postalCode, cityName);
|
||||||
await registerAPI(email, name, amicaleName, postalCode, cityName);
|
|
||||||
|
|
||||||
// Créer l'administrateur local
|
// Créer l'administrateur local
|
||||||
final int userId = apiResult['user_id'] is String
|
final int userId = apiResult['user_id'] is String ? int.parse(apiResult['user_id']) : apiResult['user_id'];
|
||||||
? int.parse(apiResult['user_id'])
|
|
||||||
: apiResult['user_id'];
|
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final newAdmin = UserModel(
|
final newAdmin = UserModel(
|
||||||
id: userId,
|
id: userId,
|
||||||
@@ -316,8 +296,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login complet avec suivi de progression
|
// Login complet avec suivi de progression
|
||||||
Future<bool> login(String username, String password,
|
Future<bool> login(String username, String password, {required String type}) async {
|
||||||
{required String type}) async {
|
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
_updateLoadingState(LoadingState.initial.copyWith(
|
_updateLoadingState(LoadingState.initial.copyWith(
|
||||||
message: 'Connexion en cours...',
|
message: 'Connexion en cours...',
|
||||||
@@ -346,8 +325,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
await Hive.deleteBoxFromDisk(boxName);
|
await Hive.deleteBoxFromDisk(boxName);
|
||||||
debugPrint('Nettoyage: Box $boxName supprimée');
|
debugPrint('Nettoyage: Box $boxName supprimée');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||||
'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
|
// Sur le web, utiliser notre méthode sécurisée pour nettoyer les boîtes Hive
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
await HiveWebFix.safeCleanHiveBoxes(
|
await HiveWebFix.safeCleanHiveBoxes(excludeBoxes: [AppKeys.userBoxName]);
|
||||||
excludeBoxes: [AppKeys.usersBoxName]);
|
|
||||||
}
|
}
|
||||||
// Sur iOS, nettoyer les fichiers Hive directement
|
// Sur iOS, nettoyer les fichiers Hive directement
|
||||||
else if (!kIsWeb && Platform.isIOS) {
|
else if (!kIsWeb && Platform.isIOS) {
|
||||||
@@ -403,8 +380,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
// Si le statut n'est pas 'success', retourner false
|
// Si le statut n'est pas 'success', retourner false
|
||||||
if (status != 'success') {
|
if (status != 'success') {
|
||||||
debugPrint('Échec de connexion: $message');
|
debugPrint('Échec de connexion: $message');
|
||||||
_updateLoadingState(
|
_updateLoadingState(LoadingState.error(message ?? 'Échec de connexion'));
|
||||||
LoadingState.error(message ?? 'Échec de connexion'));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,8 +397,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Si la clé 'user' existe, examiner son contenu
|
// Si la clé 'user' existe, examiner son contenu
|
||||||
if (apiResult['user'] != null &&
|
if (apiResult['user'] != null && apiResult['user'] is Map<String, dynamic>) {
|
||||||
apiResult['user'] is Map<String, dynamic>) {
|
|
||||||
debugPrint('Détails utilisateur:');
|
debugPrint('Détails utilisateur:');
|
||||||
final userDetails = apiResult['user'] as Map<String, dynamic>;
|
final userDetails = apiResult['user'] as Map<String, dynamic>;
|
||||||
userDetails.forEach((key, value) {
|
userDetails.forEach((key, value) {
|
||||||
@@ -430,8 +405,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Construire un UserModel à partir des données utilisateur
|
// Construire un UserModel à partir des données utilisateur
|
||||||
final user = _processUserData(
|
final user = _processUserData(userDetails, apiResult['session_id'], apiResult['session_expiry']);
|
||||||
userDetails, apiResult['session_id'], apiResult['session_expiry']);
|
|
||||||
|
|
||||||
// Supprimer les anciennes références à interface et utiliser directement le rôle
|
// Supprimer les anciennes références à interface et utiliser directement le rôle
|
||||||
await saveUser(user);
|
await saveUser(user);
|
||||||
@@ -463,8 +437,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
if (apiResult['clients'] is List) {
|
if (apiResult['clients'] is List) {
|
||||||
clientsList = apiResult['clients'] as List<dynamic>;
|
clientsList = apiResult['clients'] as List<dynamic>;
|
||||||
} else if (apiResult['clients'] is Map &&
|
} else if (apiResult['clients'] is Map && apiResult['clients'].containsKey('data')) {
|
||||||
apiResult['clients'].containsKey('data')) {
|
|
||||||
clientsList = apiResult['clients']['data'] as List<dynamic>;
|
clientsList = apiResult['clients']['data'] as List<dynamic>;
|
||||||
} else {
|
} else {
|
||||||
debugPrint('Format de données de clients non reconnu');
|
debugPrint('Format de données de clients non reconnu');
|
||||||
@@ -529,8 +502,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Traitement des membres
|
// Traitement des membres
|
||||||
if (apiResult.containsKey('membres') ||
|
if (apiResult.containsKey('membres') || apiResult.containsKey('members')) {
|
||||||
apiResult.containsKey('members')) {
|
|
||||||
final membresData = apiResult['membres'] ?? apiResult['members'];
|
final membresData = apiResult['membres'] ?? apiResult['members'];
|
||||||
if (membresData != null) {
|
if (membresData != null) {
|
||||||
await _processMembres(membresData);
|
await _processMembres(membresData);
|
||||||
@@ -547,8 +519,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
// Traitement des associations utilisateurs-secteurs
|
// Traitement des associations utilisateurs-secteurs
|
||||||
if (apiResult.containsKey('users_sectors')) {
|
if (apiResult.containsKey('users_sectors')) {
|
||||||
await _processUserSectors(apiResult['users_sectors']);
|
await _processUserSectors(apiResult['users_sectors']);
|
||||||
debugPrint(
|
debugPrint('Nombre d\'associations utilisateurs-secteurs chargées: ${_userSectorBox.length}');
|
||||||
'Nombre d\'associations utilisateurs-secteurs chargées: ${_userSectorBox.length}');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérification finale du remplissage des boîtes
|
// Vérification finale du remplissage des boîtes
|
||||||
@@ -570,8 +541,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
for (final userSector in _userSectorBox.values) {
|
for (final userSector in _userSectorBox.values) {
|
||||||
if (displayCount < 5) {
|
if (displayCount < 5) {
|
||||||
// Limiter à 5 pour éviter de surcharger la console
|
// Limiter à 5 pour éviter de surcharger la console
|
||||||
debugPrint(
|
debugPrint(' User ${userSector.id} (${userSector.firstName}) -> Secteur ${userSector.fkSector} (${userSector.name})');
|
||||||
' User ${userSector.id} (${userSector.firstName}) -> Secteur ${userSector.fkSector} (${userSector.name})');
|
|
||||||
displayCount++;
|
displayCount++;
|
||||||
} else {
|
} else {
|
||||||
debugPrint(' ... et ${userSectorCount - 5} autres associations');
|
debugPrint(' ... et ${userSectorCount - 5} autres associations');
|
||||||
@@ -591,27 +561,21 @@ class UserRepository extends ChangeNotifier {
|
|||||||
if (apiResult.containsKey('passages')) {
|
if (apiResult.containsKey('passages')) {
|
||||||
if (apiResult['passages'] is List) {
|
if (apiResult['passages'] is List) {
|
||||||
passagesCountInResponse = (apiResult['passages'] as List).length;
|
passagesCountInResponse = (apiResult['passages'] as List).length;
|
||||||
} else if (apiResult['passages'] is Map &&
|
} else if (apiResult['passages'] is Map && apiResult['passages'].containsKey('data')) {
|
||||||
apiResult['passages'].containsKey('data')) {
|
passagesCountInResponse = (apiResult['passages']['data'] as List).length;
|
||||||
passagesCountInResponse =
|
|
||||||
(apiResult['passages']['data'] as List).length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int passagesCountInBox = _passageBox.length;
|
int passagesCountInBox = _passageBox.length;
|
||||||
debugPrint(
|
debugPrint('Nombre de passages dans la réponse API: $passagesCountInResponse');
|
||||||
'Nombre de passages dans la réponse API: $passagesCountInResponse');
|
|
||||||
debugPrint('Nombre de passages dans la Hive Box: $passagesCountInBox');
|
debugPrint('Nombre de passages dans la Hive Box: $passagesCountInBox');
|
||||||
|
|
||||||
// Si les nombres ne correspondent pas, attendre un peu et revérifier
|
// Si les nombres ne correspondent pas, attendre un peu et revérifier
|
||||||
if (passagesCountInResponse > 0 &&
|
if (passagesCountInResponse > 0 && passagesCountInBox < passagesCountInResponse) {
|
||||||
passagesCountInBox < passagesCountInResponse) {
|
debugPrint('Attente supplémentaire pour finaliser le chargement des passages...');
|
||||||
debugPrint(
|
|
||||||
'Attente supplémentaire pour finaliser le chargement des passages...');
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
passagesCountInBox = _passageBox.length;
|
passagesCountInBox = _passageBox.length;
|
||||||
debugPrint(
|
debugPrint('Après attente: Nombre de passages dans la Hive Box: $passagesCountInBox');
|
||||||
'Après attente: Nombre de passages dans la Hive Box: $passagesCountInBox');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Étape 12: Chargement terminé (100%)
|
// Étape 12: Chargement terminé (100%)
|
||||||
@@ -652,7 +616,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
await Hive.openBox<OperationModel>(boxName);
|
await Hive.openBox<OperationModel>(boxName);
|
||||||
} else if (boxName == AppKeys.sectorsBoxName) {
|
} else if (boxName == AppKeys.sectorsBoxName) {
|
||||||
await Hive.openBox<SectorModel>(boxName);
|
await Hive.openBox<SectorModel>(boxName);
|
||||||
} else if (boxName == AppKeys.usersBoxName) {
|
} else if (boxName == AppKeys.userBoxName) {
|
||||||
await Hive.openBox<UserModel>(boxName);
|
await Hive.openBox<UserModel>(boxName);
|
||||||
} else if (boxName == AppKeys.membresBoxName) {
|
} else if (boxName == AppKeys.membresBoxName) {
|
||||||
await Hive.openBox<MembreModel>(boxName);
|
await Hive.openBox<MembreModel>(boxName);
|
||||||
@@ -696,15 +660,13 @@ class UserRepository extends ChangeNotifier {
|
|||||||
await Hive.deleteBoxFromDisk(boxName);
|
await Hive.deleteBoxFromDisk(boxName);
|
||||||
debugPrint('Nettoyage: Box $boxName supprimée');
|
debugPrint('Nettoyage: Box $boxName supprimée');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors de la suppression de la boîte non référencée $boxName: $e');
|
||||||
'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
|
// Sur le web, utiliser notre méthode sécurisée pour nettoyer les boîtes Hive
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
await HiveWebFix.safeCleanHiveBoxes(
|
await HiveWebFix.safeCleanHiveBoxes(excludeBoxes: [AppKeys.userBoxName]);
|
||||||
excludeBoxes: [AppKeys.usersBoxName]);
|
|
||||||
}
|
}
|
||||||
// Sur iOS, nettoyer les fichiers Hive directement
|
// Sur iOS, nettoyer les fichiers Hive directement
|
||||||
else if (Platform.isIOS) {
|
else if (Platform.isIOS) {
|
||||||
@@ -758,8 +720,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
await Hive.deleteBoxFromDisk(boxName);
|
await Hive.deleteBoxFromDisk(boxName);
|
||||||
} catch (deleteError) {
|
} catch (deleteError) {
|
||||||
debugPrint(
|
debugPrint('Impossible de supprimer la boîte $boxName: $deleteError');
|
||||||
'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
|
// Si la boîte contient des éléments, c'est anormal après recréation
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
debugPrint(
|
debugPrint('ATTENTION: La boîte $boxName contient encore des données après recréation');
|
||||||
'ATTENTION: La boîte $boxName contient encore des données après recréation');
|
|
||||||
// Essayer de vider la boîte une dernière fois
|
// Essayer de vider la boîte une dernière fois
|
||||||
await box.clear();
|
await box.clear();
|
||||||
debugPrint('Vidage forcé de la boîte $boxName effectué');
|
debugPrint('Vidage forcé de la boîte $boxName effectué');
|
||||||
}
|
}
|
||||||
} catch (typeError) {
|
} catch (typeError) {
|
||||||
debugPrint(
|
debugPrint('Erreur de typage lors de la vérification de $boxName: $typeError');
|
||||||
'Erreur de typage lors de la vérification de $boxName: $typeError');
|
|
||||||
|
|
||||||
// Tentative alternative sans typage spécifique
|
// Tentative alternative sans typage spécifique
|
||||||
try {
|
try {
|
||||||
@@ -872,17 +831,14 @@ class UserRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
await box.clear();
|
await box.clear();
|
||||||
debugPrint(
|
debugPrint('Vidage forcé de la boîte $boxName (sans typage) effectué');
|
||||||
'Vidage forcé de la boîte $boxName (sans typage) effectué');
|
|
||||||
}
|
}
|
||||||
} catch (e2) {
|
} catch (e2) {
|
||||||
debugPrint(
|
debugPrint('Impossible de vérifier la boîte $boxName même sans typage: $e2');
|
||||||
'Impossible de vérifier la boîte $boxName même sans typage: $e2');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debugPrint(
|
debugPrint('Boîte $boxName non ouverte, impossible de vérifier l\'intégrité');
|
||||||
'Boîte $boxName non ouverte, impossible de vérifier l\'intégrité');
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de la vérification de la boîte $boxName: $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');
|
debugPrint('Vérification d\'intégrité terminée');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors de la vérification d\'intégrité des boîtes Hive: $e');
|
||||||
'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");
|
var request = indexedDB.deleteDatabase("geosector_app");
|
||||||
request.onsuccess = function() { console.log("IndexedDB nettoyé avec succès"); };
|
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));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
@@ -932,7 +887,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
for (var entry in entries) {
|
for (var entry in entries) {
|
||||||
final name = entry.path.split('/').last;
|
final name = entry.path.split('/').last;
|
||||||
// Ne pas supprimer la boîte des utilisateurs
|
// Ne pas supprimer la boîte des utilisateurs
|
||||||
if (!name.contains(AppKeys.usersBoxName)) {
|
if (!name.contains(AppKeys.userBoxName)) {
|
||||||
debugPrint('Suppression de: ${entry.path}');
|
debugPrint('Suppression de: ${entry.path}');
|
||||||
if (entry is Directory) {
|
if (entry is Directory) {
|
||||||
await entry.delete(recursive: true);
|
await entry.delete(recursive: true);
|
||||||
@@ -957,7 +912,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
debugPrint('Nettoyage des fichiers Hive sur Android...');
|
debugPrint('Nettoyage des fichiers Hive sur Android...');
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
final hiveDir = Directory('${appDir.path}');
|
final hiveDir = Directory(appDir.path);
|
||||||
|
|
||||||
if (await hiveDir.exists()) {
|
if (await hiveDir.exists()) {
|
||||||
debugPrint('Recherche des fichiers Hive dans: ${hiveDir.path}');
|
debugPrint('Recherche des fichiers Hive dans: ${hiveDir.path}');
|
||||||
@@ -968,8 +923,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
for (var entry in entries) {
|
for (var entry in entries) {
|
||||||
final name = entry.path.split('/').last;
|
final name = entry.path.split('/').last;
|
||||||
// Ne supprimer que les fichiers Hive, mais pas la boîte des utilisateurs
|
// Ne supprimer que les fichiers Hive, mais pas la boîte des utilisateurs
|
||||||
if (name.endsWith('.hive') &&
|
if (name.endsWith('.hive') && !name.contains(AppKeys.userBoxName)) {
|
||||||
!name.contains(AppKeys.usersBoxName)) {
|
|
||||||
debugPrint('Suppression du fichier Hive: ${entry.path}');
|
debugPrint('Suppression du fichier Hive: ${entry.path}');
|
||||||
if (entry is File) {
|
if (entry is File) {
|
||||||
await entry.delete();
|
await entry.delete();
|
||||||
@@ -985,23 +939,19 @@ class UserRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint(
|
debugPrint('Nettoyage des fichiers Hive sur Android terminé. $filesDeleted fichiers supprimés.');
|
||||||
'Nettoyage des fichiers Hive sur Android terminé. $filesDeleted fichiers supprimés.');
|
|
||||||
} else {
|
} else {
|
||||||
debugPrint('Répertoire d\'application non trouvé');
|
debugPrint('Répertoire d\'application non trouvé');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors du nettoyage des fichiers Hive sur Android: $e');
|
||||||
'Erreur lors du nettoyage des fichiers Hive sur Android: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Méthode de connexion avec affichage d'un overlay de chargement avec progression
|
/// 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
|
/// Cette méthode remplace AuthService.login et utilise le nouvel overlay avec barre de progression
|
||||||
Future<bool> loginWithUI(
|
Future<bool> loginWithUI(BuildContext context, String username, String password, {required String type}) async {
|
||||||
BuildContext context, String username, String password,
|
|
||||||
{required String type}) async {
|
|
||||||
try {
|
try {
|
||||||
// Réinitialiser l'état de chargement
|
// Réinitialiser l'état de chargement
|
||||||
_updateLoadingState(LoadingState.initial.copyWith(
|
_updateLoadingState(LoadingState.initial.copyWith(
|
||||||
@@ -1019,7 +969,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Écouter les changements d'état pour mettre à jour l'overlay
|
// Écouter les changements d'état pour mettre à jour l'overlay
|
||||||
final listener = () {
|
listener() {
|
||||||
if (_progressOverlay != null) {
|
if (_progressOverlay != null) {
|
||||||
// Mettre à jour l'overlay avec les nouvelles valeurs
|
// Mettre à jour l'overlay avec les nouvelles valeurs
|
||||||
LoadingProgressOverlayUtils.update(
|
LoadingProgressOverlayUtils.update(
|
||||||
@@ -1029,7 +979,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
stepDescription: _loadingState.stepDescription,
|
stepDescription: _loadingState.stepDescription,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Ajouter l'écouteur
|
// Ajouter l'écouteur
|
||||||
addListener(listener);
|
addListener(listener);
|
||||||
@@ -1164,24 +1114,21 @@ class UserRepository extends ChangeNotifier {
|
|||||||
String? lastUsername;
|
String? lastUsername;
|
||||||
int? lastRole;
|
int? lastRole;
|
||||||
UserModel? lastUser;
|
UserModel? lastUser;
|
||||||
if (Hive.isBoxOpen(AppKeys.usersBoxName) && _userBox.isNotEmpty) {
|
if (Hive.isBoxOpen(AppKeys.userBoxName) && _userBox.isNotEmpty) {
|
||||||
try {
|
try {
|
||||||
// Récupérer l'utilisateur actuel ou le dernier utilisateur connecté
|
// Récupérer l'utilisateur actuel ou le dernier utilisateur connecté
|
||||||
lastUser = getCurrentUser() ?? _userBox.values.first;
|
lastUser = getCurrentUser() ?? _userBox.values.first;
|
||||||
if (lastUser != null) {
|
lastUsername = lastUser.username;
|
||||||
lastUsername = lastUser.username;
|
|
||||||
|
|
||||||
// Convertir le rôle en int si nécessaire
|
// Convertir le rôle en int si nécessaire
|
||||||
if (lastUser.role is String) {
|
if (lastUser.role is String) {
|
||||||
lastRole = int.tryParse(lastUser.role as String) ?? 0;
|
lastRole = int.tryParse(lastUser.role as String) ?? 0;
|
||||||
} else {
|
} else {
|
||||||
lastRole = lastUser.role as int;
|
lastRole = lastUser.role;
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint(
|
|
||||||
'Username sauvegardé pour pré-remplissage: $lastUsername');
|
|
||||||
debugPrint('Rôle sauvegardé pour pré-remplissage: $lastRole');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debugPrint('Username sauvegardé pour pré-remplissage: $lastUsername');
|
||||||
|
debugPrint('Rôle sauvegardé pour pré-remplissage: $lastRole');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de la sauvegarde du username et du rôle: $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
|
// 1. Vider toutes les boîtes sans les fermer
|
||||||
debugPrint('Vidage des boîtes Hive...');
|
debugPrint('Vidage des boîtes Hive...');
|
||||||
if (Hive.isBoxOpen(AppKeys.usersBoxName)) {
|
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||||
try {
|
try {
|
||||||
await _userBox.clear();
|
await _userBox.clear();
|
||||||
debugPrint('Boîte users vidée');
|
debugPrint('Boîte users vidée');
|
||||||
@@ -1200,16 +1147,14 @@ class UserRepository extends ChangeNotifier {
|
|||||||
id: lastUser?.id ?? DateTime.now().millisecondsSinceEpoch,
|
id: lastUser?.id ?? DateTime.now().millisecondsSinceEpoch,
|
||||||
email: lastUser?.email ?? '',
|
email: lastUser?.email ?? '',
|
||||||
username: lastUsername,
|
username: lastUsername,
|
||||||
role: lastRole ??
|
role: lastRole ?? 0, // Conserver le rôle pour la vérification dans la page de login
|
||||||
0, // Conserver le rôle pour la vérification dans la page de login
|
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
lastSyncedAt: DateTime.now(),
|
lastSyncedAt: DateTime.now(),
|
||||||
isActive: false,
|
isActive: false,
|
||||||
isSynced: false,
|
isSynced: false,
|
||||||
);
|
);
|
||||||
await _userBox.put(minimalUser.id, minimalUser);
|
await _userBox.put(minimalUser.id, minimalUser);
|
||||||
debugPrint(
|
debugPrint('Utilisateur minimal créé pour pré-remplissage du username avec rôle: $lastRole');
|
||||||
'Utilisateur minimal créé pour pré-remplissage du username avec rôle: $lastRole');
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors du vidage de la boîte users: $e');
|
debugPrint('Erreur lors du vidage de la boîte users: $e');
|
||||||
@@ -1266,8 +1211,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
await _chatConversationBox.clear();
|
await _chatConversationBox.clear();
|
||||||
debugPrint('Boîte chat_conversations vidée');
|
debugPrint('Boîte chat_conversations vidée');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors du vidage de la boîte chat_conversations: $e');
|
||||||
'Erreur lors du vidage de la boîte chat_conversations: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1319,15 +1263,15 @@ class UserRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Vérifier si la boîte est ouverte avant de tenter de la fermer
|
// 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...');
|
debugPrint('Fermeture de la boîte users...');
|
||||||
try {
|
try {
|
||||||
await Hive.box<UserModel>(AppKeys.usersBoxName).close();
|
await Hive.box<UserModel>(AppKeys.userBoxName).close();
|
||||||
debugPrint('Boîte users fermée avec succès');
|
debugPrint('Boîte users fermée avec succès');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de la fermeture de la boîte users: $e');
|
debugPrint('Erreur lors de la fermeture de la boîte users: $e');
|
||||||
// Ne pas continuer avec la suppression si la fermeture a échoué
|
// 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
|
// 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
|
// Supprimer la boîte du disque seulement si la fermeture a réussi
|
||||||
debugPrint('Suppression de la boîte users du disque...');
|
debugPrint('Suppression de la boîte users du disque...');
|
||||||
try {
|
try {
|
||||||
await Hive.deleteBoxFromDisk(AppKeys.usersBoxName);
|
await Hive.deleteBoxFromDisk(AppKeys.userBoxName);
|
||||||
debugPrint('Boîte users supprimée du disque avec succès');
|
debugPrint('Boîte users supprimée du disque avec succès');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de la suppression de la boîte users: $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é
|
// Ne pas continuer avec la réouverture si la suppression a échoué
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debugPrint(
|
debugPrint('La boîte users est déjà fermée, tentative de suppression directe...');
|
||||||
'La boîte users est déjà fermée, tentative de suppression directe...');
|
|
||||||
try {
|
try {
|
||||||
await Hive.deleteBoxFromDisk(AppKeys.usersBoxName);
|
await Hive.deleteBoxFromDisk(AppKeys.userBoxName);
|
||||||
debugPrint('Boîte users supprimée du disque avec succès');
|
debugPrint('Boîte users supprimée du disque avec succès');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors de la suppression directe de la boîte users: $e');
|
||||||
'Erreur lors de la suppression directe de la boîte users: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors du processus de nettoyage de la boîte users: $e');
|
||||||
'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
|
// Continuer malgré l'erreur, mais ne pas tenter de réouvrir la boîte
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1366,12 +1307,11 @@ class UserRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
// Rouvrir la boîte (elle sera vide)
|
// Rouvrir la boîte (elle sera vide)
|
||||||
debugPrint('Réouverture de la boîte users (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
|
// Vérifier que la boîte est bien vide
|
||||||
final checkUsers = _userBox.values.toList();
|
final checkUsers = _userBox.values.toList();
|
||||||
debugPrint(
|
debugPrint('Après approche radicale: ${checkUsers.length} utilisateurs restants');
|
||||||
'Après approche radicale: ${checkUsers.length} utilisateurs restants');
|
|
||||||
|
|
||||||
// Forcer la réinitialisation du cache
|
// Forcer la réinitialisation du cache
|
||||||
_cachedCurrentUser = null;
|
_cachedCurrentUser = null;
|
||||||
@@ -1486,8 +1426,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final unsyncedUsers =
|
final unsyncedUsers = _userBox.values.where((user) => !user.isSynced).toList();
|
||||||
_userBox.values.where((user) => !user.isSynced).toList();
|
|
||||||
|
|
||||||
if (unsyncedUsers.isEmpty) {
|
if (unsyncedUsers.isEmpty) {
|
||||||
return;
|
return;
|
||||||
@@ -1605,9 +1544,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
List<AmicaleModel> getAllClients() {
|
List<AmicaleModel> getAllClients() {
|
||||||
try {
|
try {
|
||||||
_ensureBoxIsOpen(AppKeys.amicaleBoxName);
|
_ensureBoxIsOpen(AppKeys.amicaleBoxName);
|
||||||
return _amicaleBox.values
|
return _amicaleBox.values.where((amicale) => amicale.fkType == 1).toList();
|
||||||
.where((amicale) => amicale.fkType == 1)
|
|
||||||
.toList();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de la récupération des clients: $e');
|
debugPrint('Erreur lors de la récupération des clients: $e');
|
||||||
return [];
|
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
|
// Méthode pour traiter les données des associations utilisateurs-secteurs reçues de l'API
|
||||||
Future<void> _processUserSectors(dynamic userSectorsData) async {
|
Future<void> _processUserSectors(dynamic userSectorsData) async {
|
||||||
try {
|
try {
|
||||||
debugPrint(
|
debugPrint('Traitement des données des associations utilisateurs-secteurs...');
|
||||||
'Traitement des données des associations utilisateurs-secteurs...');
|
|
||||||
|
|
||||||
// Vérifier que les données sont au bon format
|
// Vérifier que les données sont au bon format
|
||||||
if (userSectorsData == null) {
|
if (userSectorsData == null) {
|
||||||
debugPrint(
|
debugPrint('Aucune donnée d\'association utilisateur-secteur à traiter');
|
||||||
'Aucune donnée d\'association utilisateur-secteur à traiter');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<dynamic> userSectorsList;
|
List<dynamic> userSectorsList;
|
||||||
if (userSectorsData is List) {
|
if (userSectorsData is List) {
|
||||||
userSectorsList = userSectorsData;
|
userSectorsList = userSectorsData;
|
||||||
} else if (userSectorsData is Map &&
|
} else if (userSectorsData is Map && userSectorsData.containsKey('data')) {
|
||||||
userSectorsData.containsKey('data')) {
|
|
||||||
userSectorsList = userSectorsData['data'] as List<dynamic>;
|
userSectorsList = userSectorsData['data'] as List<dynamic>;
|
||||||
} else {
|
} else {
|
||||||
debugPrint(
|
debugPrint('Format de données d\'associations utilisateurs-secteurs non reconnu');
|
||||||
'Format de données d\'associations utilisateurs-secteurs non reconnu');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1844,26 +1777,21 @@ class UserRepository extends ChangeNotifier {
|
|||||||
for (final userSectorData in userSectorsList) {
|
for (final userSectorData in userSectorsList) {
|
||||||
try {
|
try {
|
||||||
final userSector = UserSectorModel.fromJson(userSectorData);
|
final userSector = UserSectorModel.fromJson(userSectorData);
|
||||||
await _userSectorBox.put(
|
await _userSectorBox.put('${userSector.id}_${userSector.fkSector}', userSector);
|
||||||
'${userSector.id}_${userSector.fkSector}', userSector);
|
|
||||||
count++;
|
count++;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors du traitement d\'une association utilisateur-secteur: $e');
|
||||||
'Erreur lors du traitement d\'une association utilisateur-secteur: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint(
|
debugPrint('$count associations utilisateurs-secteurs traitées et stockées');
|
||||||
'$count associations utilisateurs-secteurs traitées et stockées');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('Erreur lors du traitement des associations utilisateurs-secteurs: $e');
|
||||||
'Erreur lors du traitement des associations utilisateurs-secteurs: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Méthode pour traiter les données utilisateur reçues de l'API
|
// Méthode pour traiter les données utilisateur reçues de l'API
|
||||||
UserModel _processUserData(
|
UserModel _processUserData(Map<String, dynamic> userData, String? sessionId, String? sessionExpiry) {
|
||||||
Map<String, dynamic> userData, String? sessionId, String? sessionExpiry) {
|
|
||||||
debugPrint('Traitement des données utilisateur: ${userData.toString()}');
|
debugPrint('Traitement des données utilisateur: ${userData.toString()}');
|
||||||
|
|
||||||
// Convertir l'ID en int, qu'il soit déjà int ou string
|
// 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
|
// Convertir fk_entite en int si présent
|
||||||
final dynamic rawFkEntite = userData['fk_entite'];
|
final dynamic rawFkEntite = userData['fk_entite'];
|
||||||
final int? fkEntite = rawFkEntite != null
|
final int? fkEntite = rawFkEntite != null ? (rawFkEntite is String ? int.parse(rawFkEntite) : rawFkEntite as int) : null;
|
||||||
? (rawFkEntite is String ? int.parse(rawFkEntite) : rawFkEntite as int)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Convertir fk_titre en int si présent
|
// Convertir fk_titre en int si présent
|
||||||
final dynamic rawFkTitre = userData['fk_titre'];
|
final dynamic rawFkTitre = userData['fk_titre'];
|
||||||
final int? fkTitre = rawFkTitre != null
|
final int? fkTitre = rawFkTitre != null ? (rawFkTitre is String ? int.parse(rawFkTitre) : rawFkTitre as int) : null;
|
||||||
? (rawFkTitre is String ? int.parse(rawFkTitre) : rawFkTitre as int)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Traiter les dates si présentes
|
// Traiter les dates si présentes
|
||||||
DateTime? dateNaissance;
|
DateTime? dateNaissance;
|
||||||
if (userData['date_naissance'] != null &&
|
if (userData['date_naissance'] != null && userData['date_naissance'] != '') {
|
||||||
userData['date_naissance'] != '') {
|
|
||||||
try {
|
try {
|
||||||
dateNaissance = DateTime.parse(userData['date_naissance']);
|
dateNaissance = DateTime.parse(userData['date_naissance']);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -1929,8 +1852,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
isActive: true,
|
isActive: true,
|
||||||
isSynced: true,
|
isSynced: true,
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
sessionExpiry:
|
sessionExpiry: sessionExpiry != null ? DateTime.parse(sessionExpiry) : null,
|
||||||
sessionExpiry != null ? DateTime.parse(sessionExpiry) : null,
|
|
||||||
sectName: userData['sect_name'],
|
sectName: userData['sect_name'],
|
||||||
fkEntite: fkEntite,
|
fkEntite: fkEntite,
|
||||||
fkTitre: fkTitre,
|
fkTitre: fkTitre,
|
||||||
|
|||||||
@@ -9,6 +9,295 @@ import 'package:retry/retry.dart';
|
|||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
||||||
class ApiService {
|
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();
|
final Dio _dio = Dio();
|
||||||
late final String _baseUrl;
|
late final String _baseUrl;
|
||||||
late final String _appIdentifier;
|
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
|
/// Réinitialise complètement Hive et recrée les boîtes nécessaires
|
||||||
static Future<bool> resetAndRecreateHiveBoxes() async {
|
static Future<bool> resetAndRecreateHiveBoxes() async {
|
||||||
try {
|
try {
|
||||||
debugPrint(
|
debugPrint('HiveResetService: Début de la réinitialisation complète de Hive');
|
||||||
'HiveResetService: Début de la réinitialisation complète de Hive');
|
|
||||||
|
|
||||||
// Approche plus radicale pour le web : supprimer directement IndexedDB
|
// Approche plus radicale pour le web : supprimer directement IndexedDB
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
@@ -68,8 +67,7 @@ class HiveResetService {
|
|||||||
// Rouvrir les boîtes essentielles
|
// Rouvrir les boîtes essentielles
|
||||||
await _reopenEssentialBoxes();
|
await _reopenEssentialBoxes();
|
||||||
|
|
||||||
debugPrint(
|
debugPrint('HiveResetService: Réinitialisation complète terminée avec succès');
|
||||||
'HiveResetService: Réinitialisation complète terminée avec succès');
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('HiveResetService: Erreur lors de la réinitialisation: $e');
|
debugPrint('HiveResetService: Erreur lors de la réinitialisation: $e');
|
||||||
@@ -80,7 +78,7 @@ class HiveResetService {
|
|||||||
/// Ferme toutes les boîtes Hive ouvertes
|
/// Ferme toutes les boîtes Hive ouvertes
|
||||||
static Future<void> _closeAllBoxes() async {
|
static Future<void> _closeAllBoxes() async {
|
||||||
final boxNames = [
|
final boxNames = [
|
||||||
AppKeys.usersBoxName,
|
AppKeys.userBoxName,
|
||||||
AppKeys.amicaleBoxName,
|
AppKeys.amicaleBoxName,
|
||||||
AppKeys.clientsBoxName,
|
AppKeys.clientsBoxName,
|
||||||
AppKeys.operationsBoxName,
|
AppKeys.operationsBoxName,
|
||||||
@@ -137,7 +135,7 @@ class HiveResetService {
|
|||||||
debugPrint('HiveResetService: Réouverture des boîtes essentielles');
|
debugPrint('HiveResetService: Réouverture des boîtes essentielles');
|
||||||
|
|
||||||
// Ouvrir les boîtes essentielles au démarrage
|
// 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<AmicaleModel>(AppKeys.amicaleBoxName);
|
||||||
await Hive.openBox<ClientModel>(AppKeys.clientsBoxName);
|
await Hive.openBox<ClientModel>(AppKeys.clientsBoxName);
|
||||||
await Hive.openBox(AppKeys.settingsBoxName);
|
await Hive.openBox(AppKeys.settingsBoxName);
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ class HiveWebFix {
|
|||||||
if (!kIsWeb) return;
|
if (!kIsWeb) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: Nettoyage sécurisé des boîtes Hive en version web');
|
||||||
'HiveWebFix: Nettoyage sécurisé des boîtes Hive en version web');
|
|
||||||
|
|
||||||
// Liste des boîtes à nettoyer
|
// Liste des boîtes à nettoyer
|
||||||
final boxesToClean = [
|
final boxesToClean = [
|
||||||
@@ -36,16 +35,14 @@ class HiveWebFix {
|
|||||||
await box.clear();
|
await box.clear();
|
||||||
debugPrint('HiveWebFix: Boîte $boxName nettoyée avec succès');
|
debugPrint('HiveWebFix: Boîte $boxName nettoyée avec succès');
|
||||||
} else {
|
} else {
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: La boîte $boxName n\'est pas ouverte, ouverture temporaire');
|
||||||
'HiveWebFix: La boîte $boxName n\'est pas ouverte, ouverture temporaire');
|
|
||||||
final box = await Hive.openBox(boxName);
|
final box = await Hive.openBox(boxName);
|
||||||
await box.clear();
|
await box.clear();
|
||||||
await box.close();
|
await box.close();
|
||||||
debugPrint('HiveWebFix: Boîte $boxName nettoyée et fermée');
|
debugPrint('HiveWebFix: Boîte $boxName nettoyée et fermée');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: Erreur lors du nettoyage de la boîte $boxName: $e');
|
||||||
'HiveWebFix: Erreur lors du nettoyage de la boîte $boxName: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,14 +62,13 @@ class HiveWebFix {
|
|||||||
// Vérifier si IndexedDB est accessible
|
// Vérifier si IndexedDB est accessible
|
||||||
final isIndexedDBAvailable = js.context.hasProperty('indexedDB');
|
final isIndexedDBAvailable = js.context.hasProperty('indexedDB');
|
||||||
if (!isIndexedDBAvailable) {
|
if (!isIndexedDBAvailable) {
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: IndexedDB n\'est pas disponible dans ce navigateur');
|
||||||
'HiveWebFix: IndexedDB n\'est pas disponible dans ce navigateur');
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Liste des boîtes essentielles
|
// Liste des boîtes essentielles
|
||||||
final essentialBoxes = [
|
final essentialBoxes = [
|
||||||
AppKeys.usersBoxName,
|
AppKeys.userBoxName,
|
||||||
AppKeys.settingsBoxName,
|
AppKeys.settingsBoxName,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -80,8 +76,7 @@ class HiveWebFix {
|
|||||||
for (final boxName in essentialBoxes) {
|
for (final boxName in essentialBoxes) {
|
||||||
try {
|
try {
|
||||||
if (!Hive.isBoxOpen(boxName)) {
|
if (!Hive.isBoxOpen(boxName)) {
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: Ouverture de la boîte essentielle $boxName');
|
||||||
'HiveWebFix: Ouverture de la boîte essentielle $boxName');
|
|
||||||
await Hive.openBox(boxName);
|
await Hive.openBox(boxName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,15 +84,13 @@ class HiveWebFix {
|
|||||||
final box = Hive.box(boxName);
|
final box = Hive.box(boxName);
|
||||||
// Tenter une opération simple pour vérifier l'intégrité
|
// Tenter une opération simple pour vérifier l'intégrité
|
||||||
final length = box.length;
|
final length = box.length;
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: Boîte $boxName accessible avec $length éléments');
|
||||||
'HiveWebFix: Boîte $boxName accessible avec $length éléments');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('HiveWebFix: Erreur d\'accès à la boîte $boxName: $e');
|
debugPrint('HiveWebFix: Erreur d\'accès à la boîte $boxName: $e');
|
||||||
|
|
||||||
// Tenter de réparer en réinitialisant Hive
|
// Tenter de réparer en réinitialisant Hive
|
||||||
try {
|
try {
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: Tentative de réparation de la boîte $boxName');
|
||||||
'HiveWebFix: Tentative de réparation de la boîte $boxName');
|
|
||||||
// Fermer la boîte si elle est ouverte
|
// Fermer la boîte si elle est ouverte
|
||||||
if (Hive.isBoxOpen(boxName)) {
|
if (Hive.isBoxOpen(boxName)) {
|
||||||
await Hive.box(boxName).close();
|
await Hive.box(boxName).close();
|
||||||
@@ -107,8 +100,7 @@ class HiveWebFix {
|
|||||||
await Hive.openBox(boxName);
|
await Hive.openBox(boxName);
|
||||||
debugPrint('HiveWebFix: Boîte $boxName réparée avec succès');
|
debugPrint('HiveWebFix: Boîte $boxName réparée avec succès');
|
||||||
} catch (repairError) {
|
} catch (repairError) {
|
||||||
debugPrint(
|
debugPrint('HiveWebFix: Échec de la réparation de la boîte $boxName: $repairError');
|
||||||
'HiveWebFix: Échec de la réparation de la boîte $boxName: $repairError');
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,7 +124,7 @@ class HiveWebFix {
|
|||||||
|
|
||||||
// Fermer toutes les boîtes ouvertes
|
// Fermer toutes les boîtes ouvertes
|
||||||
final boxesToClose = [
|
final boxesToClose = [
|
||||||
AppKeys.usersBoxName,
|
AppKeys.userBoxName,
|
||||||
AppKeys.operationsBoxName,
|
AppKeys.operationsBoxName,
|
||||||
AppKeys.sectorsBoxName,
|
AppKeys.sectorsBoxName,
|
||||||
AppKeys.passagesBoxName,
|
AppKeys.passagesBoxName,
|
||||||
|
|||||||
@@ -133,7 +133,110 @@ void _registerHiveAdapters() {
|
|||||||
/// Ouvre les boîtes Hive essentielles
|
/// Ouvre les boîtes Hive essentielles
|
||||||
Future<void> _openEssentialHiveBoxes() async {
|
Future<void> _openEssentialHiveBoxes() async {
|
||||||
final boxesToOpen = [
|
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.amicaleBoxName, 'type': 'AmicaleModel'},
|
||||||
{'name': AppKeys.clientsBoxName, 'type': 'ClientModel'},
|
{'name': AppKeys.clientsBoxName, 'type': 'ClientModel'},
|
||||||
{'name': AppKeys.settingsBoxName, 'type': 'dynamic'},
|
{'name': AppKeys.settingsBoxName, 'type': 'dynamic'},
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ class DotsPainter extends CustomPainter {
|
|||||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SplashPageState extends State<SplashPage>
|
class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateMixin {
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late AnimationController _animationController;
|
late AnimationController _animationController;
|
||||||
late Animation<double> _scaleAnimation;
|
late Animation<double> _scaleAnimation;
|
||||||
bool _isInitializing = true;
|
bool _isInitializing = true;
|
||||||
@@ -72,9 +71,7 @@ class _SplashPageState extends State<SplashPage>
|
|||||||
// Fallback sur la version du AppInfoService si elle existe
|
// Fallback sur la version du AppInfoService si elle existe
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_appVersion = AppInfoService.fullVersion
|
_appVersion = AppInfoService.fullVersion.split(' ').last; // Extraire juste le numéro
|
||||||
.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
|
// Structure pour les boîtes à ouvrir avec leurs noms d'affichage
|
||||||
final boxesToOpen = [
|
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.amicaleBoxName, 'display': 'Préparation amicale'},
|
||||||
{'name': AppKeys.clientsBoxName, 'display': 'Préparation clients'},
|
{'name': AppKeys.clientsBoxName, 'display': 'Préparation clients'},
|
||||||
{'name': AppKeys.regionsBoxName, 'display': 'Préparation régions'},
|
{'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.sectorsBoxName, 'display': 'Préparation secteurs'},
|
||||||
{'name': AppKeys.passagesBoxName, 'display': 'Préparation passages'},
|
{'name': AppKeys.passagesBoxName, 'display': 'Préparation passages'},
|
||||||
{'name': AppKeys.membresBoxName, 'display': 'Préparation membres'},
|
{'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.settingsBoxName, 'display': 'Préparation paramètres'},
|
||||||
{
|
{'name': AppKeys.chatConversationsBoxName, 'display': 'Préparation conversations'},
|
||||||
'name': AppKeys.chatConversationsBoxName,
|
{'name': AppKeys.chatMessagesBoxName, 'display': 'Préparation messages'},
|
||||||
'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)
|
// 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)...');
|
debugPrint('Ouverture de la boîte $boxName ($displayName)...');
|
||||||
|
|
||||||
// Ouvrir la boîte avec le type approprié
|
// Ouvrir la boîte avec le type approprié
|
||||||
if (boxName == AppKeys.usersBoxName) {
|
if (boxName == AppKeys.userBoxName) {
|
||||||
await Hive.openBox<UserModel>(boxName);
|
await Hive.openBox<UserModel>(boxName);
|
||||||
} else if (boxName == AppKeys.amicaleBoxName) {
|
} else if (boxName == AppKeys.amicaleBoxName) {
|
||||||
await Hive.openBox<AmicaleModel>(boxName);
|
await Hive.openBox<AmicaleModel>(boxName);
|
||||||
@@ -296,7 +281,7 @@ class _SplashPageState extends State<SplashPage>
|
|||||||
),
|
),
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: DotsPainter(),
|
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',
|
'Une application puissante et intuitive de gestion de vos distributions de calendriers',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: theme.textTheme.bodyLarge?.copyWith(
|
style: theme.textTheme.bodyLarge?.copyWith(
|
||||||
color:
|
color: theme.colorScheme.onSurface.withOpacity(0.7),
|
||||||
theme.colorScheme.onBackground.withOpacity(0.7),
|
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -380,8 +364,7 @@ class _SplashPageState extends State<SplashPage>
|
|||||||
Text(
|
Text(
|
||||||
_statusMessage,
|
_statusMessage,
|
||||||
style: theme.textTheme.bodyMedium?.copyWith(
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
color:
|
color: theme.colorScheme.onSurface.withOpacity(0.7),
|
||||||
theme.colorScheme.onBackground.withOpacity(0.7),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -394,8 +377,7 @@ class _SplashPageState extends State<SplashPage>
|
|||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go(
|
context.go('/login/user'); // Utiliser la route spécifique
|
||||||
'/login/user'); // Utiliser la route spécifique
|
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.green,
|
backgroundColor: Colors.green,
|
||||||
@@ -426,8 +408,7 @@ class _SplashPageState extends State<SplashPage>
|
|||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go(
|
context.go('/login/admin'); // Utiliser la route spécifique
|
||||||
'/login/admin'); // Utiliser la route spécifique
|
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
@@ -451,8 +432,7 @@ class _SplashPageState extends State<SplashPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(
|
const SizedBox(height: 32), // 2 espaces sous le bouton précédent
|
||||||
height: 32), // 2 espaces sous le bouton précédent
|
|
||||||
|
|
||||||
// Bouton d'inscription
|
// Bouton d'inscription
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
|
|||||||
Reference in New Issue
Block a user