feat: création branche singletons - début refactorisation

- Sauvegarde des fichiers critiques
- Préparation transformation ApiService en singleton
- Préparation création CurrentUserService et CurrentAmicaleService
- Objectif: renommer Box users -> user
This commit is contained in:
d6soft
2025-06-05 15:22:29 +02:00
parent 2aa2706179
commit e5ab857913
48 changed files with 131679 additions and 128324 deletions

View File

@@ -37,6 +37,9 @@ class MembreModel extends HiveObject {
@HiveField(10)
final String email;
@HiveField(11)
final int fkEntite;
MembreModel({
required this.id,
required this.fkRole,
@@ -49,6 +52,7 @@ class MembreModel extends HiveObject {
required this.name,
required this.username,
required this.email,
required this.fkEntite,
});
// Factory pour convertir depuis JSON (API)
@@ -63,13 +67,15 @@ class MembreModel extends HiveObject {
// Convertir le titre en int, qu'il soit déjà int ou string
final dynamic rawTitre = json['fk_titre'];
final int fkTitre =
rawTitre is String ? int.parse(rawTitre) : rawTitre as int;
final int fkTitre = rawTitre is String ? int.parse(rawTitre) : rawTitre as int;
// Convertir le chkActive en int, qu'il soit déjà int ou string
final dynamic rawActive = json['chk_active'];
final int chkActive =
rawActive is String ? int.parse(rawActive) : rawActive as int;
final int chkActive = rawActive is String ? int.parse(rawActive) : rawActive as int;
// Convertir le fkEntite en int, qu'il soit déjà int ou string
final dynamic rawEntite = json['fk_entite'];
final int fkEntite = rawEntite is String ? int.parse(rawEntite) : rawEntite as int;
return MembreModel(
id: id,
@@ -77,16 +83,13 @@ class MembreModel extends HiveObject {
fkTitre: fkTitre,
firstName: json['first_name'] ?? '',
sectName: json['sect_name'],
dateNaissance: json['date_naissance'] != null
? DateTime.parse(json['date_naissance'])
: null,
dateEmbauche: json['date_embauche'] != null
? DateTime.parse(json['date_embauche'])
: null,
dateNaissance: json['date_naissance'] != null ? DateTime.parse(json['date_naissance']) : null,
dateEmbauche: json['date_embauche'] != null ? DateTime.parse(json['date_embauche']) : null,
chkActive: chkActive,
name: json['name'] ?? '',
username: json['username'] ?? '',
email: json['email'] ?? '',
fkEntite: fkEntite,
);
}
@@ -104,6 +107,7 @@ class MembreModel extends HiveObject {
'name': name,
'username': username,
'email': email,
'fk_entite': fkEntite,
};
}
@@ -119,9 +123,10 @@ class MembreModel extends HiveObject {
String? name,
String? username,
String? email,
int? fkEntite,
}) {
return MembreModel(
id: this.id,
id: id,
fkRole: fkRole ?? this.fkRole,
fkTitre: fkTitre ?? this.fkTitre,
firstName: firstName ?? this.firstName,
@@ -132,6 +137,7 @@ class MembreModel extends HiveObject {
name: name ?? this.name,
username: username ?? this.username,
email: email ?? this.email,
fkEntite: fkEntite ?? this.fkEntite,
);
}
}

View File

@@ -28,13 +28,14 @@ class MembreModelAdapter extends TypeAdapter<MembreModel> {
name: fields[8] as String,
username: fields[9] as String,
email: fields[10] as String,
fkEntite: fields[11] as int,
);
}
@override
void write(BinaryWriter writer, MembreModel obj) {
writer
..writeByte(11)
..writeByte(12)
..writeByte(0)
..write(obj.id)
..writeByte(1)
@@ -56,7 +57,9 @@ class MembreModelAdapter extends TypeAdapter<MembreModel> {
..writeByte(9)
..write(obj.username)
..writeByte(10)
..write(obj.email);
..write(obj.email)
..writeByte(11)
..write(obj.fkEntite);
}
@override

View File

@@ -7,8 +7,7 @@ import 'package:geosector_app/core/data/models/amicale_model.dart';
class AmicaleRepository extends ChangeNotifier {
// Utilisation de getters lazy pour n'accéder à la boîte que lorsque nécessaire
Box<AmicaleModel> get _amicaleBox =>
Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
Box<AmicaleModel> get _amicaleBox => Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
final ApiService _apiService;
bool _isLoading = false;
@@ -18,6 +17,19 @@ class AmicaleRepository extends ChangeNotifier {
// Getters
bool get isLoading => _isLoading;
// Méthode pour exposer la Box Hive (nécessaire pour ValueListenableBuilder)
Box<AmicaleModel> getAmicalesBox() {
try {
if (!Hive.isBoxOpen(AppKeys.amicaleBoxName)) {
throw Exception('La boîte amicales n\'est pas ouverte');
}
return _amicaleBox;
} catch (e) {
debugPrint('Erreur lors de l\'accès à la boîte amicales: $e');
rethrow;
}
}
// Méthode pour vérifier si une boîte est ouverte et l'ouvrir si nécessaire
Future<void> _ensureBoxIsOpen() async {
try {
@@ -59,8 +71,7 @@ class AmicaleRepository extends ChangeNotifier {
_ensureBoxIsOpen();
return _amicaleBox.get(fkEntite);
} catch (e) {
debugPrint(
'Erreur lors de la récupération de l\'amicale de l\'utilisateur: $e');
debugPrint('Erreur lors de la récupération de l\'amicale de l\'utilisateur: $e');
return null;
}
}
@@ -146,8 +157,7 @@ class AmicaleRepository extends ChangeNotifier {
final amicale = AmicaleModel.fromJson(amicaleMap);
await _amicaleBox.put(amicale.id, amicale);
count++;
debugPrint(
'Amicale unique traitée: ${amicale.name} (ID: ${amicale.id})');
debugPrint('Amicale unique traitée: ${amicale.name} (ID: ${amicale.id})');
} catch (e) {
debugPrint('Erreur lors du traitement de l\'amicale unique: $e');
debugPrint('Exception détaillée: $e');
@@ -177,8 +187,7 @@ class AmicaleRepository extends ChangeNotifier {
await processAmicalesData(amicalesData);
return getAllAmicales();
} else {
debugPrint(
'Erreur lors de la récupération des amicales: ${response.statusCode}');
debugPrint('Erreur lors de la récupération des amicales: ${response.statusCode}');
return [];
}
} catch (e) {
@@ -204,8 +213,7 @@ class AmicaleRepository extends ChangeNotifier {
await saveAmicale(amicale);
return amicale;
} else {
debugPrint(
'Erreur lors de la récupération de l\'amicale: ${response.statusCode}');
debugPrint('Erreur lors de la récupération de l\'amicale: ${response.statusCode}');
return null;
}
} catch (e) {
@@ -234,8 +242,7 @@ class AmicaleRepository extends ChangeNotifier {
await saveAmicale(updatedAmicale);
return updatedAmicale;
} else {
debugPrint(
'Erreur lors de la mise à jour de l\'amicale: ${response.statusCode}');
debugPrint('Erreur lors de la mise à jour de l\'amicale: ${response.statusCode}');
return null;
}
} catch (e) {
@@ -254,23 +261,17 @@ class AmicaleRepository extends ChangeNotifier {
}
final lowercaseQuery = query.toLowerCase();
return _amicaleBox.values
.where((amicale) => amicale.name.toLowerCase().contains(lowercaseQuery))
.toList();
return _amicaleBox.values.where((amicale) => amicale.name.toLowerCase().contains(lowercaseQuery)).toList();
}
// Filtrer les amicales par type
List<AmicaleModel> getAmicalesByType(int type) {
return _amicaleBox.values
.where((amicale) => amicale.fkType == type)
.toList();
return _amicaleBox.values.where((amicale) => amicale.fkType == type).toList();
}
// Filtrer les amicales par région
List<AmicaleModel> getAmicalesByRegion(int regionId) {
return _amicaleBox.values
.where((amicale) => amicale.fkRegion == regionId)
.toList();
return _amicaleBox.values.where((amicale) => amicale.fkRegion == regionId).toList();
}
// Filtrer les amicales actives
@@ -280,16 +281,12 @@ class AmicaleRepository extends ChangeNotifier {
// Filtrer les amicales par code postal
List<AmicaleModel> getAmicalesByPostalCode(String postalCode) {
return _amicaleBox.values
.where((amicale) => amicale.codePostal == postalCode)
.toList();
return _amicaleBox.values.where((amicale) => amicale.codePostal == postalCode).toList();
}
// Filtrer les amicales par ville
List<AmicaleModel> getAmicalesByCity(String city) {
final lowercaseCity = city.toLowerCase();
return _amicaleBox.values
.where((amicale) => amicale.ville.toLowerCase().contains(lowercaseCity))
.toList();
return _amicaleBox.values.where((amicale) => amicale.ville.toLowerCase().contains(lowercaseCity)).toList();
}
}

View File

@@ -8,8 +8,7 @@ import 'package:geosector_app/core/data/models/membre_model.dart';
class MembreRepository extends ChangeNotifier {
// Utilisation de getters lazy pour n'accéder à la boîte que lorsque nécessaire
Box<MembreModel> get _membreBox =>
Hive.box<MembreModel>(AppKeys.membresBoxName);
Box<MembreModel> get _membreBox => Hive.box<MembreModel>(AppKeys.membresBoxName);
final ApiService _apiService;
bool _isLoading = false;
@@ -20,6 +19,19 @@ class MembreRepository extends ChangeNotifier {
bool get isLoading => _isLoading;
List<MembreModel> get membres => getAllMembres();
// Méthode pour exposer la Box Hive (nécessaire pour ValueListenableBuilder)
Box<MembreModel> getMembresBox() {
try {
if (!Hive.isBoxOpen(AppKeys.membresBoxName)) {
throw Exception('La boîte membres n\'est pas ouverte');
}
return Hive.box<MembreModel>(AppKeys.membresBoxName);
} catch (e) {
debugPrint('Erreur lors de l\'accès à la boîte membres: $e');
rethrow;
}
}
// Méthode pour vérifier si une boîte est ouverte et l'ouvrir si nécessaire
Future<void> _ensureBoxIsOpen() async {
try {
@@ -29,10 +41,37 @@ class MembreRepository extends ChangeNotifier {
debugPrint('Boîte ${AppKeys.membresBoxName} ouverte avec succès');
}
} catch (e) {
debugPrint(
'Erreur lors de l\'ouverture de la boîte ${AppKeys.membresBoxName}: $e');
throw Exception(
'Impossible d\'ouvrir la boîte ${AppKeys.membresBoxName}: $e');
debugPrint('Erreur lors de l\'ouverture de la boîte ${AppKeys.membresBoxName}: $e');
throw Exception('Impossible d\'ouvrir la boîte ${AppKeys.membresBoxName}: $e');
}
}
List<MembreModel> getMembresByAmicale(int fkEntite) {
try {
return _membreBox.values.where((membre) => membre.fkEntite == fkEntite).toList();
} catch (e) {
debugPrint('Erreur lors de la récupération des membres par amicale: $e');
return [];
}
}
// Récupérer les membres actifs par amicale
List<MembreModel> getActiveMembresByAmicale(int fkEntite) {
try {
return _membreBox.values.where((membre) => membre.fkEntite == fkEntite && membre.chkActive == 1).toList();
} catch (e) {
debugPrint('Erreur lors de la récupération des membres actifs par amicale: $e');
return [];
}
}
// Compter les membres par amicale
int countMembresByAmicale(int fkEntite) {
try {
return _membreBox.values.where((membre) => membre.fkEntite == fkEntite).length;
} catch (e) {
debugPrint('Erreur lors du comptage des membres par amicale: $e');
return 0;
}
}
@@ -79,8 +118,7 @@ class MembreRepository extends ChangeNotifier {
try {
final hasConnection = await _apiService.hasInternetConnection();
if (!hasConnection) {
debugPrint(
'Pas de connexion Internet, utilisation des données locales');
debugPrint('Pas de connexion Internet, utilisation des données locales');
return getAllMembres();
}
@@ -107,8 +145,7 @@ class MembreRepository extends ChangeNotifier {
notifyListeners();
return membres;
} catch (e) {
debugPrint(
'Erreur lors de la récupération des membres depuis l\'API: $e');
debugPrint('Erreur lors de la récupération des membres depuis l\'API: $e');
return getAllMembres();
} finally {
_isLoading = false;
@@ -129,8 +166,7 @@ class MembreRepository extends ChangeNotifier {
}
// Endpoint à adapter selon votre API
final response =
await _apiService.post('/membres', data: membre.toJson());
final response = await _apiService.post('/membres', data: membre.toJson());
final membreData = response.data['membre'];
final newMembre = MembreModel.fromJson(membreData);
@@ -154,14 +190,12 @@ class MembreRepository extends ChangeNotifier {
try {
final hasConnection = await _apiService.hasInternetConnection();
if (!hasConnection) {
debugPrint(
'Pas de connexion Internet, impossible de mettre à jour le membre');
debugPrint('Pas de connexion Internet, impossible de mettre à jour le membre');
return null;
}
// Endpoint à adapter selon votre API
final response =
await _apiService.put('/membres/${membre.id}', data: membre.toJson());
final response = await _apiService.put('/membres/${membre.id}', data: membre.toJson());
final membreData = response.data['membre'];
final updatedMembre = MembreModel.fromJson(membreData);
@@ -185,8 +219,7 @@ class MembreRepository extends ChangeNotifier {
try {
final hasConnection = await _apiService.hasInternetConnection();
if (!hasConnection) {
debugPrint(
'Pas de connexion Internet, impossible de supprimer le membre');
debugPrint('Pas de connexion Internet, impossible de supprimer le membre');
return false;
}

View File

@@ -13,16 +13,16 @@ class ApiService {
late final String _baseUrl;
late final String _appIdentifier;
String? _sessionId;
// 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')) {
@@ -31,11 +31,11 @@ class ApiService {
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;
@@ -49,23 +49,23 @@ class ApiService {
_baseUrl = AppKeys.baseApiUrlProd;
_appIdentifier = AppKeys.appIdentifierProd;
}
debugPrint('GEOSECTOR 🔗 Environnement: $env, API: $_baseUrl');
}
ApiService() {
// Configurer l'environnement
_configureEnvironment();
// Configurer Dio
_dio.options.baseUrl = _baseUrl;
_dio.options.connectTimeout = AppKeys.connectionTimeout;
_dio.options.receiveTimeout = AppKeys.receiveTimeout;
// Ajouter les en-têtes par défaut avec l'identifiant d'application adapté à l'environnement
final headers = Map<String, String>.from(AppKeys.defaultHeaders);
headers['X-App-Identifier'] = _appIdentifier;
_dio.options.headers.addAll(headers);
// Ajouter des intercepteurs pour l'authentification par session
@@ -89,17 +89,17 @@ class ApiService {
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;
@@ -119,7 +119,7 @@ class ApiService {
rethrow;
}
}
// Méthode GET générique
Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {
try {
@@ -128,7 +128,7 @@ class ApiService {
rethrow;
}
}
// Méthode PUT générique
Future<Response> put(String path, {dynamic data}) async {
try {
@@ -137,7 +137,7 @@ class ApiService {
rethrow;
}
}
// Méthode DELETE générique
Future<Response> delete(String path) async {
try {
@@ -159,7 +159,7 @@ class ApiService {
// 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?;
@@ -203,9 +203,7 @@ class ApiService {
retryIf: (e) => e is SocketException || e is TimeoutException,
);
return (response.data as List)
.map((json) => UserModel.fromJson(json))
.toList();
return (response.data as List).map((json) => UserModel.fromJson(json)).toList();
} catch (e) {
// Gérer les erreurs
rethrow;