diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 26b0936..f536956 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -9,6 +9,7 @@
+
diff --git a/devtools_options.yaml b/devtools_options.yaml
index fa0b357..2bc8e05 100644
--- a/devtools_options.yaml
+++ b/devtools_options.yaml
@@ -1,3 +1,4 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
+ - provider: true
\ No newline at end of file
diff --git a/flutter_01.png b/flutter_01.png
deleted file mode 100644
index e69de29..0000000
diff --git a/flutter_02.png b/flutter_02.png
deleted file mode 100644
index f5cd612..0000000
Binary files a/flutter_02.png and /dev/null differ
diff --git a/flutter_03.png b/flutter_03.png
deleted file mode 100644
index 8ba7e4d..0000000
Binary files a/flutter_03.png and /dev/null differ
diff --git a/flutter_04.png b/flutter_04.png
deleted file mode 100644
index c45b299..0000000
Binary files a/flutter_04.png and /dev/null differ
diff --git a/lib/assets/animations/friend_expanding_card.dart b/lib/assets/animations/friend_expanding_card.dart
new file mode 100644
index 0000000..1827f43
--- /dev/null
+++ b/lib/assets/animations/friend_expanding_card.dart
@@ -0,0 +1,141 @@
+import 'package:flutter/material.dart';
+
+/// [FriendExpandingCard] est un widget animé qui s'agrandit pour afficher des options supplémentaires.
+/// Il permet de voir plus de détails, d'envoyer un message ou de supprimer un ami.
+class FriendExpandingCard extends StatefulWidget {
+ final String name;
+ final String imageUrl;
+ final String description;
+ final VoidCallback onTap;
+ final VoidCallback onMessageTap;
+ final VoidCallback onRemoveTap;
+
+ const FriendExpandingCard({
+ Key? key,
+ required this.name,
+ required this.imageUrl,
+ required this.description,
+ required this.onTap,
+ required this.onMessageTap,
+ required this.onRemoveTap,
+ }) : super(key: key);
+
+ @override
+ _FriendExpandingCardState createState() => _FriendExpandingCardState();
+}
+
+class _FriendExpandingCardState extends State {
+ bool _isExpanded = false;
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: widget.onTap,
+ onLongPress: () {
+ setState(() {
+ _isExpanded = !_isExpanded;
+ });
+ },
+ child: AnimatedContainer(
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ height: _isExpanded ? 200 : 100,
+ margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 5),
+ padding: const EdgeInsets.all(10),
+ decoration: BoxDecoration(
+ color: Colors.grey.shade900,
+ borderRadius: BorderRadius.circular(16),
+ boxShadow: const [
+ BoxShadow(
+ color: Colors.black26,
+ blurRadius: 10,
+ offset: Offset(2, 2),
+ ),
+ ],
+ ),
+ child: Column(
+ children: [
+ Row(
+ children: [
+ Hero(
+ tag: widget.name,
+ child: CircleAvatar(
+ backgroundImage: NetworkImage(widget.imageUrl),
+ radius: 30,
+ ),
+ ),
+ const SizedBox(width: 16),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ widget.name,
+ style: const TextStyle(
+ color: Colors.white,
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ const SizedBox(height: 5),
+ AnimatedOpacity(
+ opacity: _isExpanded ? 1.0 : 0.0,
+ duration: const Duration(milliseconds: 300),
+ child: Text(
+ widget.description,
+ style: const TextStyle(
+ color: Colors.white70,
+ fontSize: 14,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ if (_isExpanded)
+ IconButton(
+ icon: const Icon(Icons.close, color: Colors.white54),
+ onPressed: () {
+ setState(() {
+ _isExpanded = false;
+ });
+ },
+ ),
+ ],
+ ),
+ if (_isExpanded) ...[
+ const SizedBox(height: 10),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ ElevatedButton.icon(
+ onPressed: widget.onMessageTap,
+ icon: const Icon(Icons.message, color: Colors.white),
+ label: const Text('Message'),
+ style: ElevatedButton.styleFrom(
+ iconColor: Colors.green,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ ),
+ ),
+ ElevatedButton.icon(
+ onPressed: widget.onRemoveTap,
+ icon: const Icon(Icons.delete, color: Colors.red),
+ label: const Text('Remove'),
+ style: ElevatedButton.styleFrom(
+ iconColor: Colors.redAccent,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(20),
+ ),
+ ),
+ ),
+ ],
+ )
+ ]
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/assets/images/default_avatar.png b/lib/assets/images/default_avatar.png
new file mode 100644
index 0000000..3392c86
Binary files /dev/null and b/lib/assets/images/default_avatar.png differ
diff --git a/lib/config/router.dart b/lib/config/router.dart
index 966491d..fabe7f9 100644
--- a/lib/config/router.dart
+++ b/lib/config/router.dart
@@ -8,33 +8,43 @@ import 'package:afterwork/presentation/screens/event/event_screen.dart';
import 'package:afterwork/data/datasources/event_remote_data_source.dart';
import '../presentation/reservations/reservations_screen.dart';
-/// Router personnalisé pour gérer la navigation dans l'application.
-/// Les logs permettent de tracer chaque navigation dans la console.
+/// [AppRouter] gère la navigation dans l'application.
+/// Chaque navigation est loguée pour assurer une traçabilité dans la console.
class AppRouter {
final EventRemoteDataSource eventRemoteDataSource;
final String userId;
final String userName;
final String userLastName;
- /// Initialisation des informations utilisateur et source de données
+ /// Constructeur de [AppRouter] initialisant les informations utilisateur
+ /// et la source de données pour les événements.
+ ///
+ /// [eventRemoteDataSource] : Source de données pour les événements.
+ /// [userId], [userName], [userLastName] : Informations de l'utilisateur.
AppRouter({
required this.eventRemoteDataSource,
required this.userId,
required this.userName,
required this.userLastName,
}) {
- print("AppRouter initialisé avec les infos utilisateur : $userId, $userName, $userLastName");
+ // Log d'initialisation avec les informations utilisateur
+ debugPrint("[LOG] AppRouter initialisé avec les infos utilisateur : $userId, $userName, $userLastName");
}
- /// Génération des routes pour l'application
+ /// Génère une route en fonction du [RouteSettings] fourni.
+ ///
+ /// Logue chaque navigation en fonction du nom de la route.
Route generateRoute(RouteSettings settings) {
- print("Navigation vers la route : ${settings.name}");
+ // Log de la navigation vers la route
+ debugPrint("[LOG] Navigation vers la route : ${settings.name}");
switch (settings.name) {
case '/':
+ debugPrint("[LOG] Chargement de l'écran de connexion");
return MaterialPageRoute(builder: (_) => const LoginScreen());
case '/home':
+ debugPrint("[LOG] Chargement de l'écran d'accueil avec l'ID utilisateur : $userId");
return MaterialPageRoute(
builder: (_) => HomeScreen(
eventRemoteDataSource: eventRemoteDataSource,
@@ -46,6 +56,7 @@ class AppRouter {
);
case '/event':
+ debugPrint("[LOG] Chargement de l'écran d'événement pour l'utilisateur : $userId");
return MaterialPageRoute(
builder: (_) => EventScreen(
userId: userId,
@@ -55,21 +66,28 @@ class AppRouter {
);
case '/story':
+ debugPrint("[LOG] Chargement de l'écran des histoires");
return MaterialPageRoute(builder: (_) => const StoryScreen());
case '/profile':
+ debugPrint("[LOG] Chargement de l'écran du profil");
return MaterialPageRoute(builder: (_) => const ProfileScreen());
case '/settings':
+ debugPrint("[LOG] Chargement de l'écran des paramètres");
return MaterialPageRoute(builder: (_) => const SettingsScreen());
case '/reservations':
+ debugPrint("[LOG] Chargement de l'écran des réservations");
return MaterialPageRoute(builder: (_) => const ReservationsScreen());
default:
+ debugPrint("[ERROR] Route non trouvée : ${settings.name}");
return MaterialPageRoute(
builder: (_) => const Scaffold(
- body: Center(child: Text('Page non trouvée')),
+ body: Center(
+ child: Text('Page non trouvée'),
+ ),
),
);
}
diff --git a/lib/core/constants/urls.dart b/lib/core/constants/urls.dart
index 8a5f9d4..8983bf0 100644
--- a/lib/core/constants/urls.dart
+++ b/lib/core/constants/urls.dart
@@ -1,5 +1,5 @@
class Urls {
- static const String baseUrl = 'http://192.168.1.145:8085';
+ static const String baseUrl = 'http://192.168.1.11:8085';
// Authentication and Users Endpoints
static const String authenticateUser = '$baseUrl/users/authenticate';
diff --git a/lib/data/datasources/user_remote_data_source.dart b/lib/data/datasources/user_remote_data_source.dart
index 92bcc65..c2935fb 100644
--- a/lib/data/datasources/user_remote_data_source.dart
+++ b/lib/data/datasources/user_remote_data_source.dart
@@ -5,136 +5,181 @@ import 'package:http/http.dart' as http;
import '../../core/errors/exceptions.dart';
/// Classe pour gérer les opérations API pour les utilisateurs.
-/// Chaque action est loguée pour faciliter la traçabilité et le débogage.
+/// Toutes les actions sont loguées pour faciliter la traçabilité et le débogage.
class UserRemoteDataSource {
+ // Client HTTP injecté pour réaliser les appels réseau
final http.Client client;
/// Constructeur avec injection du client HTTP
UserRemoteDataSource(this.client);
- /// Authentifie un utilisateur avec l'email et le mot de passe en clair.
+ /// Authentifie un utilisateur avec l'email et le mot de passe.
/// Si l'authentification réussit, retourne un objet `UserModel`.
+ /// Les erreurs sont gérées et toutes les actions sont loguées.
Future authenticateUser(String email, String password) async {
- print("Tentative d'authentification pour l'email : $email");
+ print("[LOG] Tentative d'authentification pour l'email : $email");
try {
- // Requête POST avec l'email et le mot de passe en clair
+ // Préparation des données d'authentification à envoyer
+ final Map body = {
+ 'email': email,
+ 'motDePasse': password,
+ };
+
+ print("[DEBUG] Données envoyées pour authentification : $body");
+
+ // Envoi de la requête HTTP POST pour authentifier l'utilisateur
final response = await client.post(
Uri.parse('${Urls.baseUrl}/users/authenticate'),
headers: {'Content-Type': 'application/json'},
- body: jsonEncode({
- 'email': email,
- 'motDePasse': password, // Le mot de passe est envoyé en clair pour le moment
- }),
+ body: jsonEncode(body),
);
- print("Réponse du serveur pour l'authentification : ${response.statusCode} - ${response.body}");
+ // Log de la réponse reçue du serveur
+ print("[LOG] Réponse du serveur : ${response.statusCode} - ${response.body}");
if (response.statusCode == 200) {
- // Si l'authentification réussit, retourne l'utilisateur
- return UserModel.fromJson(jsonDecode(response.body));
+ final userData = jsonDecode(response.body);
+
+ if (userData['userId'] != null && userData['userId'].isNotEmpty) {
+ print("[LOG] Utilisateur authentifié avec succès. ID: ${userData['userId']}");
+ return UserModel.fromJson(userData);
+ } else {
+ print("[ERROR] L'ID utilisateur est manquant dans la réponse.");
+ throw Exception("ID utilisateur manquant.");
+ }
} else if (response.statusCode == 401) {
- // Gestion des erreurs d'authentification
- throw UnauthorizedException();
+ print("[ERROR] Authentification échouée : Mot de passe incorrect.");
+ throw UnauthorizedException("Mot de passe incorrect.");
} else {
- throw ServerException();
+ print("[ERROR] Erreur du serveur. Code : ${response.statusCode}");
+ throw ServerExceptionWithMessage("Erreur inattendue : ${response.body}");
}
} catch (e) {
- print("Erreur d'authentification : $e");
+ print("[ERROR] Erreur lors de l'authentification : $e");
throw Exception("Erreur lors de l'authentification : $e");
}
}
- /// Récupère un utilisateur par son identifiant et logue les étapes.
+ /// Récupère un utilisateur par son identifiant.
+ /// Les erreurs et les succès sont logués pour un suivi complet.
Future getUser(String id) async {
- print("Tentative de récupération de l'utilisateur avec l'ID : $id");
+ print("[LOG] Tentative de récupération de l'utilisateur avec l'ID : $id");
try {
+ // Envoi de la requête GET pour obtenir l'utilisateur par son ID
final response = await client.get(Uri.parse('${Urls.baseUrl}/users/$id'));
- print("Réponse du serveur pour getUser : ${response.statusCode} - ${response.body}");
+ print("[LOG] Réponse du serveur pour getUser : ${response.statusCode} - ${response.body}");
if (response.statusCode == 200) {
+ // Utilisateur trouvé, retour de l'objet UserModel
return UserModel.fromJson(json.decode(response.body));
- } else if (response.statusCode == 404) {
- print("Utilisateur non trouvé.");
+ }
+ // Gestion du cas où l'utilisateur n'est pas trouvé
+ else if (response.statusCode == 404) {
+ print("[ERROR] Utilisateur non trouvé.");
throw UserNotFoundException();
- } else {
+ }
+ // Gestion des autres erreurs serveur
+ else {
+ print("[ERROR] Erreur du serveur lors de la récupération de l'utilisateur.");
throw ServerException();
}
} catch (e) {
- print("Erreur lors de la récupération de l'utilisateur : $e");
+ print("[ERROR] Erreur lors de la récupération de l'utilisateur : $e");
throw Exception("Erreur lors de la récupération de l'utilisateur : $e");
}
}
- /// Crée un nouvel utilisateur et logue les détails de la requête.
+ /// Crée un nouvel utilisateur dans le backend.
+ /// Toutes les actions, succès ou erreurs sont logués pour un suivi précis.
Future createUser(UserModel user) async {
- print("Création d'un nouvel utilisateur : ${user.toJson()}");
+ print("[LOG] Création d'un nouvel utilisateur : ${user.toJson()}");
try {
+ // Envoi de la requête POST pour créer un nouvel utilisateur
final response = await client.post(
Uri.parse('${Urls.baseUrl}/users'),
headers: {'Content-Type': 'application/json'},
- body: jsonEncode(user.toJson()),
+ body: jsonEncode(user.toJson()), // Conversion du modèle utilisateur en JSON
);
- print("Réponse du serveur pour createUser : ${response.statusCode} - ${response.body}");
+ print("[LOG] Réponse du serveur pour createUser : ${response.statusCode} - ${response.body}");
if (response.statusCode == 201) {
+ // Utilisateur créé avec succès
return UserModel.fromJson(json.decode(response.body));
- } else if (response.statusCode == 409) {
- // Gestion des conflits (utilisateur déjà existant)
+ }
+ // Gestion des conflits (ex: utilisateur déjà existant)
+ else if (response.statusCode == 409) {
+ print("[ERROR] Conflit lors de la création de l'utilisateur : Utilisateur déjà existant.");
throw ConflictException();
- } else {
+ }
+ // Gestion des autres erreurs serveur
+ else {
+ print("[ERROR] Erreur du serveur lors de la création de l'utilisateur.");
throw ServerException();
}
} catch (e) {
- print("Erreur lors de la création de l'utilisateur : $e");
+ print("[ERROR] Erreur lors de la création de l'utilisateur : $e");
throw Exception("Erreur lors de la création de l'utilisateur : $e");
}
}
- /// Met à jour un utilisateur existant et logue les étapes.
+ /// Met à jour un utilisateur existant.
+ /// Chaque étape est loguée pour faciliter le débogage.
Future updateUser(UserModel user) async {
- print("Mise à jour de l'utilisateur : ${user.toJson()}");
+ print("[LOG] Mise à jour de l'utilisateur : ${user.toJson()}");
try {
+ // Envoi de la requête PUT pour mettre à jour un utilisateur
final response = await client.put(
Uri.parse('${Urls.baseUrl}/users/${user.userId}'),
headers: {'Content-Type': 'application/json'},
- body: jsonEncode(user.toJson()),
+ body: jsonEncode(user.toJson()), // Conversion du modèle utilisateur en JSON
);
- print("Réponse du serveur pour updateUser : ${response.statusCode} - ${response.body}");
+ print("[LOG] Réponse du serveur pour updateUser : ${response.statusCode} - ${response.body}");
if (response.statusCode == 200) {
+ // Mise à jour réussie
return UserModel.fromJson(json.decode(response.body));
- } else if (response.statusCode == 404) {
- // Gestion des cas où l'utilisateur n'est pas trouvé
+ }
+ // Gestion du cas où l'utilisateur n'est pas trouvé
+ else if (response.statusCode == 404) {
+ print("[ERROR] Utilisateur non trouvé.");
throw UserNotFoundException();
- } else {
+ }
+ // Gestion des autres erreurs serveur
+ else {
+ print("[ERROR] Erreur du serveur lors de la mise à jour de l'utilisateur.");
throw ServerException();
}
} catch (e) {
- print("Erreur lors de la mise à jour de l'utilisateur : $e");
+ print("[ERROR] Erreur lors de la mise à jour de l'utilisateur : $e");
throw Exception("Erreur lors de la mise à jour de l'utilisateur : $e");
}
}
- /// Supprime un utilisateur et logue chaque étape.
+ /// Supprime un utilisateur par son identifiant.
+ /// Les erreurs et succès sont logués pour garantir un suivi complet.
Future deleteUser(String id) async {
- print("Tentative de suppression de l'utilisateur avec l'ID : $id");
+ print("[LOG] Tentative de suppression de l'utilisateur avec l'ID : $id");
try {
+ // Envoi de la requête DELETE pour supprimer un utilisateur
final response = await client.delete(Uri.parse('${Urls.baseUrl}/users/$id'));
- print("Réponse du serveur pour deleteUser : ${response.statusCode} - ${response.body}");
+ print("[LOG] Réponse du serveur pour deleteUser : ${response.statusCode} - ${response.body}");
- if (response.statusCode != 204) {
- print("Erreur lors de la suppression de l'utilisateur.");
+ // Vérification du succès de la suppression
+ if (response.statusCode == 204) {
+ print("[LOG] Utilisateur supprimé avec succès.");
+ }
+ // Gestion des autres erreurs serveur
+ else {
+ print("[ERROR] Erreur du serveur lors de la suppression de l'utilisateur.");
throw ServerException();
- } else {
- print("Utilisateur supprimé avec succès.");
}
} catch (e) {
- print("Erreur lors de la suppression de l'utilisateur : $e");
+ print("[ERROR] Erreur lors de la suppression de l'utilisateur : $e");
throw Exception("Erreur lors de la suppression de l'utilisateur : $e");
}
}
diff --git a/lib/data/models/social_post_model.dart b/lib/data/models/social_post_model.dart
new file mode 100644
index 0000000..2effe2b
--- /dev/null
+++ b/lib/data/models/social_post_model.dart
@@ -0,0 +1,23 @@
+class SocialPost {
+ final String userName;
+ final String userImage;
+ final String postText;
+ final String postImage;
+ final int likes;
+ final int comments;
+ final int shares;
+ final List badges; // Gamification badges
+ final List tags; // Ajout de tags pour personnalisation des posts
+
+ SocialPost({
+ required this.userName,
+ required this.userImage,
+ required this.postText,
+ required this.postImage,
+ required this.likes,
+ required this.comments,
+ required this.shares,
+ required this.badges,
+ this.tags = const [],
+ });
+}
diff --git a/lib/data/models/user_model.dart b/lib/data/models/user_model.dart
index 7fae62f..e0b1e58 100644
--- a/lib/data/models/user_model.dart
+++ b/lib/data/models/user_model.dart
@@ -20,7 +20,7 @@ class UserModel extends User {
/// Factory pour créer un `UserModel` à partir d'un JSON reçu depuis l'API.
factory UserModel.fromJson(Map json) {
return UserModel(
- userId: json['id'] ?? '',
+ userId: json['userId'] ?? '',
nom: json['nom'] ?? 'Inconnu',
prenoms: json['prenoms'] ?? 'Inconnu',
email: json['email'] ?? 'inconnu@example.com',
diff --git a/lib/data/providers/friends_provider.dart b/lib/data/providers/friends_provider.dart
new file mode 100644
index 0000000..2b69c7c
--- /dev/null
+++ b/lib/data/providers/friends_provider.dart
@@ -0,0 +1,159 @@
+import 'package:flutter/material.dart';
+import 'package:logger/logger.dart';
+import '../../domain/entities/friend.dart';
+import '../../data/repositories/friends_repository_impl.dart';
+
+/// [FriendsProvider] est un `ChangeNotifier` qui gère la logique de gestion des amis.
+/// Il utilise [FriendsRepositoryImpl] pour interagir avec l'API et assure la gestion des états,
+/// comme le chargement, la pagination et les erreurs éventuelles.
+class FriendsProvider with ChangeNotifier {
+ final FriendsRepositoryImpl friendsRepository;
+ final Logger _logger = Logger(); // Logger pour suivre toutes les actions.
+
+ // Liste privée des amis récupérée depuis l'API
+ List _friendsList = [];
+ bool _isLoading = false; // Indique si une opération de chargement est en cours
+ bool _hasMore = true; // Indique s'il reste des amis à charger
+ int _currentPage = 0;
+ final int _friendsPerPage = 10; // Nombre d'amis par page pour la pagination
+
+ /// Constructeur de [FriendsProvider] qui requiert une instance de [FriendsRepositoryImpl].
+ FriendsProvider({required this.friendsRepository});
+
+ // Getters pour accéder aux états depuis l'interface utilisateur
+ bool get isLoading => _isLoading;
+ bool get hasMore => _hasMore;
+ List get friendsList => _friendsList;
+
+ /// Récupère la liste paginée des amis pour un utilisateur donné.
+ ///
+ /// [userId] : L'identifiant unique de l'utilisateur.
+ /// [loadMore] : Indique s'il s'agit d'une demande de chargement supplémentaire pour la pagination.
+ ///
+ /// En cas d'erreur, logue l'exception et gère l'état `isLoading`.
+ Future fetchFriends(String userId, {bool loadMore = false}) async {
+ if (_isLoading) {
+ _logger.w('[LOG] Chargement déjà en cours, annulation de la nouvelle demande.');
+ return;
+ }
+
+ _isLoading = true;
+ notifyListeners();
+ _logger.i('[LOG] Début du chargement des amis.');
+
+ if (!loadMore) {
+ // Réinitialisation de la liste et de la pagination si ce n'est pas un chargement supplémentaire
+ _friendsList = [];
+ _currentPage = 0;
+ _hasMore = true;
+ _logger.i('[LOG] Réinitialisation de la pagination et de la liste des amis.');
+ }
+
+ try {
+ _logger.i('[LOG] Chargement de la page $_currentPage des amis pour l\'utilisateur $userId.');
+ final newFriends = await friendsRepository.fetchFriends(userId, _currentPage, _friendsPerPage);
+
+ if (newFriends.isEmpty) {
+ _hasMore = false;
+ _logger.i('[LOG] Fin de liste atteinte, plus d\'amis à charger.');
+ } else {
+ _friendsList.addAll(newFriends);
+ _currentPage++;
+ _logger.i('[LOG] Amis ajoutés à la liste. Page actuelle : $_currentPage');
+ }
+ } catch (e) {
+ _logger.e('[ERROR] Erreur lors de la récupération des amis : $e');
+ } finally {
+ _isLoading = false;
+ _logger.i('[LOG] Fin du chargement des amis.');
+ notifyListeners();
+ }
+ }
+
+ /// Supprime un ami dans l'API et met à jour la liste localement.
+ ///
+ /// [friendId] : Identifiant unique de l'ami à supprimer.
+ ///
+ /// Loggue chaque étape pour assurer un suivi précis de l'opération.
+ Future removeFriend(String friendId) async {
+ try {
+ _logger.i('[LOG] Tentative de suppression de l\'ami avec l\'ID : $friendId');
+ await friendsRepository.removeFriend(friendId);
+ _friendsList.removeWhere((friend) => friend.friendId == friendId);
+ _logger.i('[LOG] Ami supprimé localement avec succès : $friendId');
+ } catch (e) {
+ _logger.e('[ERROR] Erreur lors de la suppression de l\'ami : $e');
+ } finally {
+ notifyListeners();
+ }
+ }
+
+ /// Récupère les détails d'un ami via l'API.
+ ///
+ /// [userId] : L'identifiant de l'utilisateur connecté.
+ /// [friendId] : Identifiant unique de l'ami.
+ ///
+ /// Retourne un `Future` contenant les détails ou `null` en cas d'erreur.
+ Future fetchFriendDetails(String userId, String friendId) async {
+ try {
+ _logger.i('[LOG] Tentative de récupération des détails de l\'ami avec l\'ID : $friendId');
+ final friendDetails = await friendsRepository.getFriendDetails(friendId, userId);
+
+ if (friendDetails != null) {
+ _logger.i('[LOG] Détails de l\'ami récupérés avec succès : ${friendDetails.friendId}');
+ } else {
+ _logger.w('[LOG] Détails de l\'ami introuvables pour l\'ID : $friendId');
+ }
+
+ return friendDetails;
+ } catch (e) {
+ _logger.e('[ERROR] Exception lors de la récupération des détails de l\'ami : $e');
+ return null;
+ }
+ }
+
+ /// Convertit un statut sous forme de chaîne en [FriendStatus].
+ ///
+ /// [status] : Le statut sous forme de chaîne.
+ ///
+ /// Retourne un [FriendStatus] correspondant, ou `FriendStatus.unknown` si non reconnu.
+ FriendStatus _convertToFriendStatus(String status) {
+ switch (status.toLowerCase()) {
+ case 'pending':
+ return FriendStatus.pending;
+ case 'accepted':
+ return FriendStatus.accepted;
+ case 'blocked':
+ return FriendStatus.blocked;
+ default:
+ return FriendStatus.unknown;
+ }
+ }
+
+ /// Met à jour le statut d'un ami (par exemple : accepter, bloquer).
+ ///
+ /// [friendId] : Identifiant unique de l'ami.
+ /// [status] : Nouveau statut pour l'ami sous forme de chaîne de caractères.
+ ///
+ /// Loggue l'action, convertit le statut en `FriendStatus`, et met à jour la liste localement.
+ Future updateFriendStatus(String friendId, String status) async {
+ try {
+ _logger.i('[LOG] Tentative de mise à jour du statut de l\'ami avec l\'ID : $friendId');
+
+ // Conversion du `String` en `FriendStatus` pour l'update locale
+ final friendStatus = _convertToFriendStatus(status);
+ await friendsRepository.updateFriendStatus(friendId, status);
+
+ // Mise à jour locale de la liste pour afficher le changement de statut
+ final friendIndex = _friendsList.indexWhere((friend) => friend.friendId == friendId);
+ if (friendIndex != -1) {
+ _friendsList[friendIndex] = _friendsList[friendIndex].copyWith(status: friendStatus);
+ _logger.i('[LOG] Statut de l\'ami mis à jour localement pour l\'ID : $friendId');
+ }
+ } catch (e) {
+ _logger.e('[ERROR] Erreur lors de la mise à jour du statut de l\'ami : $e');
+ } finally {
+ notifyListeners();
+ }
+ }
+}
diff --git a/lib/data/providers/user_provider.dart b/lib/data/providers/user_provider.dart
index 6f0a68c..dbb7e9c 100644
--- a/lib/data/providers/user_provider.dart
+++ b/lib/data/providers/user_provider.dart
@@ -1,18 +1,53 @@
import 'package:flutter/material.dart';
+/// [UserProvider] est un `ChangeNotifier` qui gère les informations de l'utilisateur.
+/// Toutes les modifications et actions sont loguées pour assurer une traçabilité complète dans le terminal.
class UserProvider with ChangeNotifier {
String _userId = '';
String _userName = '';
String _userLastName = '';
+ /// Getter pour l'ID de l'utilisateur
String get userId => _userId;
+
+ /// Getter pour le nom de l'utilisateur
String get userName => _userName;
+
+ /// Getter pour le prénom de l'utilisateur
String get userLastName => _userLastName;
+ /// Méthode pour définir les informations de l'utilisateur.
+ /// Logue les informations fournies et notifie les listeners des changements.
+ ///
+ /// [id] : L'ID de l'utilisateur.
+ /// [name] : Le nom de l'utilisateur.
+ /// [lastName] : Le prénom de l'utilisateur.
void setUser(String id, String name, String lastName) {
+ debugPrint("[LOG] Tentative de définition des informations de l'utilisateur : ID = $id, Nom = $name, Prénom = $lastName");
+
_userId = id;
_userName = name;
_userLastName = lastName;
+
+ debugPrint("[LOG] Informations utilisateur définies : ID = $_userId, Nom = $_userName, Prénom = $_userLastName");
+
+ // Notifie les widgets écoutant ce provider qu'une modification a eu lieu
+ notifyListeners();
+ }
+
+ /// Méthode pour réinitialiser les informations de l'utilisateur.
+ /// Les valeurs sont loguées avant et après la réinitialisation.
+ void resetUser() {
+ debugPrint("[LOG] Réinitialisation des informations de l'utilisateur.");
+ debugPrint("[LOG] Valeurs avant réinitialisation : ID = $_userId, Nom = $_userName, Prénom = $_userLastName");
+
+ _userId = '';
+ _userName = '';
+ _userLastName = '';
+
+ debugPrint("[LOG] Informations utilisateur réinitialisées : ID = $_userId, Nom = $_userName, Prénom = $_userLastName");
+
+ // Notifie les widgets écoutant ce provider que l'utilisateur a été réinitialisé
notifyListeners();
}
}
diff --git a/lib/data/repositories/friends_repository.dart b/lib/data/repositories/friends_repository.dart
new file mode 100644
index 0000000..baa8ed6
--- /dev/null
+++ b/lib/data/repositories/friends_repository.dart
@@ -0,0 +1,48 @@
+import 'package:afterwork/domain/entities/friend.dart';
+
+/// Interface [FriendsRepository] définissant les méthodes pour gérer les amis.
+/// Cette interface permet de séparer la logique métier des appels API et de la gestion des données.
+/// Elle est implémentée par [FriendsRepositoryImpl], qui contient les détails d'implémentation.
+abstract class FriendsRepository {
+
+ /// Récupère la liste paginée des amis pour un utilisateur donné via l'API.
+ ///
+ /// [userId] : Identifiant unique de l'utilisateur pour lequel récupérer la liste d'amis.
+ /// [currentPage] : Indique la page actuelle pour la pagination.
+ /// [friendsPerPage] : Nombre d'amis à récupérer par page.
+ ///
+ /// Retourne une liste d'objets [Friend] correspondant aux amis de l'utilisateur.
+ /// En cas d'échec, une liste vide peut être retournée par l'implémentation.
+ Future> fetchFriends(String userId, int currentPage, int friendsPerPage);
+
+ /// Envoie une demande pour ajouter un nouvel ami via l'API.
+ ///
+ /// [friend] : Objet [Friend] représentant l'ami à ajouter.
+ ///
+ /// Retourne un `Future`. En cas d'erreur, l'implémentation peut lancer une exception.
+ Future addFriend(Friend friend);
+
+ /// Supprime un ami existant via l'API.
+ ///
+ /// [friendId] : Identifiant unique de l'ami à supprimer.
+ ///
+ /// Retourne un `Future`. En cas d'erreur, l'implémentation peut lancer une exception.
+ Future removeFriend(String friendId);
+
+ /// Récupère les détails d'un ami en utilisant son identifiant `friendId`.
+ ///
+ /// [userId] : Identifiant unique de l'utilisateur connecté (facultatif selon le contexte).
+ /// [friendId] : Identifiant unique de l'ami pour lequel récupérer les détails.
+ ///
+ /// Retourne un `Future` contenant les informations de l'ami si trouvées,
+ /// ou `null` si aucun ami correspondant n'est trouvé ou en cas d'échec.
+ Future getFriendDetails(String friendId, String userId);
+
+ /// Met à jour le statut d'un ami dans le système (par exemple, accepter, bloquer).
+ ///
+ /// [friendId] : Identifiant unique de l'ami.
+ /// [status] : Nouveau statut de l'ami sous forme de chaîne de caractères.
+ ///
+ /// Retourne un `Future`. En cas d'erreur, l'implémentation peut lancer une exception.
+ Future updateFriendStatus(String friendId, String status);
+}
diff --git a/lib/data/repositories/friends_repository_impl.dart b/lib/data/repositories/friends_repository_impl.dart
new file mode 100644
index 0000000..87bf3ff
--- /dev/null
+++ b/lib/data/repositories/friends_repository_impl.dart
@@ -0,0 +1,175 @@
+import 'dart:convert';
+import 'package:flutter/cupertino.dart';
+import 'package:http/http.dart' as http;
+import 'package:logger/logger.dart';
+import '../../core/constants/urls.dart';
+import '../../domain/entities/friend.dart';
+import 'friends_repository.dart';
+
+/// Implémentation de [FriendsRepository] pour gérer les appels API relatifs aux amis.
+/// Chaque action est loguée pour une traçabilité complète et une gestion des erreurs avancée.
+class FriendsRepositoryImpl implements FriendsRepository {
+ final http.Client client;
+ final Logger _logger = Logger(); // Logger pour suivre toutes les actions.
+
+ FriendsRepositoryImpl({required this.client});
+
+ /// Récupère la liste paginée des amis pour un utilisateur donné via l'API.
+ ///
+ /// [userId] : Identifiant unique de l'utilisateur.
+ /// [page] : Page actuelle pour la pagination.
+ /// [size] : Nombre d'amis par page.
+ ///
+ /// Retourne une liste d'objets [Friend] ou une liste vide en cas d'erreur.
+ @override
+ Future> fetchFriends(String userId, int page, int size) async {
+ try {
+ _logger.i("[LOG] Chargement des amis pour l'utilisateur : $userId, page : $page, taille : $size");
+
+ final uri = Uri.parse('${Urls.baseUrl}/friends/list/$userId?page=$page&size=$size');
+ _logger.d('[LOG] URL appelée : $uri');
+
+ final response = await client.get(uri);
+
+ if (response.statusCode == 200) {
+ _logger.i("[LOG] Liste des amis récupérée avec succès.");
+
+ final List friendsJson = json.decode(response.body);
+ _logger.i("[LOG] Nombre d'amis récupérés : ${friendsJson.length}");
+
+ return friendsJson.map((json) => Friend.fromJson(json as Map)).toList();
+ } else {
+ _logger.e("[ERROR] Échec de la récupération des amis. Code HTTP : ${response.statusCode}");
+ return [];
+ }
+ } catch (e) {
+ _logger.e("[ERROR] Exception lors de la récupération des amis : $e");
+ return [];
+ }
+ }
+
+ /// Envoie une demande pour ajouter un nouvel ami via l'API.
+ ///
+ /// [friend] : Objet [Friend] représentant l'ami à ajouter.
+ ///
+ /// Loggue chaque étape et lève une exception en cas d'erreur.
+ @override
+ Future addFriend(Friend friend) async {
+ try {
+ _logger.i("[LOG] Tentative d'ajout de l'ami : ${friend.firstName} ${friend.lastName}");
+
+ final uri = Uri.parse('${Urls.baseUrl}/friends/send');
+ final response = await client.post(
+ uri,
+ headers: {'Content-Type': 'application/json'},
+ body: json.encode(friend.toJson()),
+ );
+
+ if (response.statusCode == 200) {
+ _logger.i("[LOG] Ami ajouté avec succès : ${friend.friendId}");
+ } else {
+ _logger.e("[ERROR] Échec lors de l'ajout de l'ami. Code HTTP : ${response.statusCode}");
+ throw Exception("Erreur lors de l'ajout de l'ami");
+ }
+ } catch (e) {
+ _logger.e("[ERROR] Exception lors de l'ajout de l'ami : $e");
+ rethrow;
+ }
+ }
+
+ /// Supprime un ami existant via l'API.
+ ///
+ /// [friendId] : Identifiant unique de l'ami à supprimer.
+ ///
+ /// Loggue l'action et lève une exception en cas d'erreur.
+ @override
+ Future removeFriend(String friendId) async {
+ try {
+ _logger.i("[LOG] Tentative de suppression de l'ami avec l'ID : $friendId");
+
+ final uri = Uri.parse('${Urls.baseUrl}/friends/$friendId');
+ final response = await client.delete(uri);
+
+ if (response.statusCode == 200) {
+ _logger.i("[LOG] Ami supprimé avec succès : $friendId");
+ } else {
+ _logger.e("[ERROR] Échec lors de la suppression de l'ami. Code HTTP : ${response.statusCode}");
+ throw Exception("Erreur lors de la suppression de l'ami");
+ }
+ } catch (e) {
+ _logger.e("[ERROR] Exception lors de la suppression de l'ami : $e");
+ rethrow;
+ }
+ }
+
+ /// Récupère les détails d'un ami en utilisant son identifiant `friendId`.
+ ///
+ /// [friendId] : Identifiant unique de l'ami.
+ /// [userId] : Identifiant unique de l'utilisateur connecté.
+ ///
+ /// Retourne un `Future` avec les informations de l'ami ou `null` en cas d'échec.
+ @override
+ Future getFriendDetails(String friendId, String userId) async {
+ try {
+ _logger.i("[LOG] Récupération des détails de l'ami avec ID : $friendId pour l'utilisateur : $userId");
+
+ final uri = Uri.parse('${Urls.baseUrl}/friends/details');
+ _logger.d("[LOG] URL pour les détails de l'ami : $uri");
+
+ final headers = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ final body = jsonEncode({
+ 'friendId': friendId,
+ 'userId': userId,
+ });
+
+ final response = await client.post(uri, headers: headers, body: body);
+ _logger.d("[LOG] Réponse de l'API : ${response.body}");
+
+ if (response.statusCode == 200) {
+ final friendJson = json.decode(response.body);
+ _logger.i("[LOG] Détails de l'ami récupérés : $friendJson");
+ return Friend.fromJson(friendJson);
+ } else {
+ _logger.e("[ERROR] Échec de la récupération des détails. Code HTTP : ${response.statusCode}");
+ return null;
+ }
+ } catch (e) {
+ _logger.e("[ERROR] Exception lors de la récupération des détails de l'ami : $e");
+ return null;
+ }
+ }
+
+ /// Met à jour le statut d'un ami (par exemple, "accepté", "bloqué").
+ ///
+ /// [friendId] : Identifiant unique de l'ami.
+ /// [status] : Nouveau statut sous forme de chaîne de caractères.
+ ///
+ /// Loggue chaque étape et lève une exception en cas d'échec.
+ @override
+ Future updateFriendStatus(String friendId, String status) async {
+ try {
+ _logger.i("[LOG] Mise à jour du statut de l'ami avec l'ID : $friendId, nouveau statut : $status");
+
+ final uri = Uri.parse('${Urls.baseUrl}/friends/$friendId/status');
+ final response = await client.patch(
+ uri,
+ headers: {'Content-Type': 'application/json'},
+ body: jsonEncode({'status': status}),
+ );
+
+ if (response.statusCode == 200) {
+ _logger.i("[LOG] Statut de l'ami mis à jour avec succès : $friendId");
+ } else {
+ _logger.e("[ERROR] Erreur lors de la mise à jour du statut. Code HTTP : ${response.statusCode}");
+ throw Exception("Erreur lors de la mise à jour du statut");
+ }
+ } catch (e) {
+ _logger.e("[ERROR] Exception lors de la mise à jour du statut de l'ami : $e");
+ rethrow;
+ }
+ }
+}
diff --git a/lib/data/services/preferences_helper.dart b/lib/data/services/preferences_helper.dart
index edb80d5..7780379 100644
--- a/lib/data/services/preferences_helper.dart
+++ b/lib/data/services/preferences_helper.dart
@@ -3,80 +3,96 @@ import 'package:shared_preferences/shared_preferences.dart';
/// Classe pour gérer les préférences utilisateur à l'aide de SharedPreferences.
/// Permet de stocker et récupérer des informations de manière non sécurisée,
/// contrairement au stockage sécurisé qui est utilisé pour des données sensibles.
+/// Chaque action est loguée pour assurer la traçabilité complète dans le terminal.
class PreferencesHelper {
// Initialisation de SharedPreferences en tant que Future
final Future _prefs = SharedPreferences.getInstance();
/// Sauvegarde une chaîne de caractères (String) dans les préférences.
+ /// Les actions sont loguées et les erreurs capturées pour garantir une sauvegarde correcte.
Future setString(String key, String value) async {
- print("Sauvegarde dans les préférences : clé = $key, valeur = $value");
+ print("[LOG] Sauvegarde dans les préférences : clé = $key, valeur = $value");
final prefs = await _prefs;
- await prefs.setString(key, value);
- print("Sauvegarde réussie pour la clé : $key");
+ final success = await prefs.setString(key, value);
+ if (success) {
+ print("[LOG] Sauvegarde réussie pour la clé : $key");
+ } else {
+ print("[ERROR] Échec de la sauvegarde pour la clé : $key");
+ }
}
/// Récupère une chaîne de caractères depuis les préférences.
+ /// Retourne la valeur ou null si aucune donnée n'est trouvée.
Future getString(String key) async {
- print("Récupération depuis les préférences pour la clé : $key");
+ print("[LOG] Récupération depuis les préférences pour la clé : $key");
final prefs = await _prefs;
final value = prefs.getString(key);
- print("Valeur récupérée pour la clé $key : $value");
+ print("[LOG] Valeur récupérée pour la clé $key : $value");
return value;
}
/// Supprime une entrée dans les préférences.
+ /// Logue chaque étape de la suppression.
Future remove(String key) async {
- print("Suppression dans les préférences pour la clé : $key");
+ print("[LOG] Suppression dans les préférences pour la clé : $key");
final prefs = await _prefs;
- await prefs.remove(key);
- print("Suppression réussie pour la clé : $key");
+ final success = await prefs.remove(key);
+ if (success) {
+ print("[LOG] Suppression réussie pour la clé : $key");
+ } else {
+ print("[ERROR] Échec de la suppression pour la clé : $key");
+ }
}
/// Sauvegarde l'identifiant utilisateur dans les préférences.
+ /// Logue l'action et assure la robustesse de l'opération.
Future saveUserId(String userId) async {
- print("Sauvegarde de l'userId dans les préférences : $userId");
+ print("[LOG] Sauvegarde de l'userId dans les préférences : $userId");
await setString('user_id', userId);
- print("Sauvegarde réussie de l'userId.");
}
/// Récupère l'identifiant utilisateur depuis les préférences.
+ /// Retourne l'ID ou null en cas d'échec.
Future getUserId() async {
- print("Récupération de l'userId depuis les préférences.");
+ print("[LOG] Récupération de l'userId depuis les préférences.");
return await getString('user_id');
}
/// Sauvegarde le nom d'utilisateur dans les préférences.
+ /// Logue l'opération pour assurer un suivi complet.
Future saveUserName(String userName) async {
- print("Sauvegarde du userName dans les préférences : $userName");
+ print("[LOG] Sauvegarde du userName dans les préférences : $userName");
await setString('user_name', userName);
- print("Sauvegarde réussie du userName.");
}
/// Récupère le nom d'utilisateur depuis les préférences.
+ /// Retourne le nom ou null en cas d'échec.
Future getUserName() async {
- print("Récupération du userName depuis les préférences.");
+ print("[LOG] Récupération du userName depuis les préférences.");
return await getString('user_name');
}
/// Sauvegarde le prénom de l'utilisateur dans les préférences.
+ /// Logue l'opération pour assurer un suivi complet.
Future saveUserLastName(String userLastName) async {
- print("Sauvegarde du userLastName dans les préférences : $userLastName");
+ print("[LOG] Sauvegarde du userLastName dans les préférences : $userLastName");
await setString('user_last_name', userLastName);
- print("Sauvegarde réussie du userLastName.");
}
/// Récupère le prénom de l'utilisateur depuis les préférences.
+ /// Retourne le prénom ou null en cas d'échec.
Future getUserLastName() async {
- print("Récupération du userLastName depuis les préférences.");
+ print("[LOG] Récupération du userLastName depuis les préférences.");
return await getString('user_last_name');
}
/// Supprime toutes les informations utilisateur dans les préférences.
+ /// Logue chaque étape de la suppression.
Future clearUserInfo() async {
- print("Suppression des informations utilisateur (userId, userName, userLastName) des préférences.");
+ print("[LOG] Suppression des informations utilisateur (userId, userName, userLastName) des préférences.");
await remove('user_id');
await remove('user_name');
await remove('user_last_name');
- print("Suppression réussie des informations utilisateur.");
+ print("[LOG] Suppression réussie des informations utilisateur.");
}
}
diff --git a/lib/data/services/secure_storage.dart b/lib/data/services/secure_storage.dart
index 6ccea61..6dba42c 100644
--- a/lib/data/services/secure_storage.dart
+++ b/lib/data/services/secure_storage.dart
@@ -1,78 +1,137 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+import 'package:logger/logger.dart';
-/// Classe pour gérer le stockage sécurisé dans l'application.
-/// Utilise FlutterSecureStorage pour stocker, lire et supprimer des données sensibles.
+/// Classe SecureStorage pour gérer les opérations de stockage sécurisé.
+/// Toutes les actions sont loguées pour permettre une traçabilité complète dans le terminal.
class SecureStorage {
- // Instance de FlutterSecureStorage pour gérer le stockage sécurisé
+ // Instance de FlutterSecureStorage pour le stockage sécurisé.
final FlutterSecureStorage _storage = const FlutterSecureStorage();
+ // Logger pour suivre et enregistrer les actions dans le terminal.
+ final Logger _logger = Logger();
+
/// Écrit une valeur dans le stockage sécurisé avec la clé spécifiée.
+ /// Les actions sont loguées et les erreurs sont capturées pour assurer la robustesse.
Future write(String key, String value) async {
- print("Écriture dans le stockage sécurisé : clé = $key, valeur = $value");
- await _storage.write(key: key, value: value);
- print("Écriture réussie pour la clé : $key");
+ try {
+ _logger.i("[LOG] Tentative d'écriture dans le stockage sécurisé : clé = $key, valeur = $value");
+ await _storage.write(key: key, value: value);
+ _logger.i("[LOG] Écriture réussie pour la clé : $key");
+ } catch (e) {
+ _logger.e("[ERROR] Échec d'écriture pour la clé $key : $e");
+ rethrow;
+ }
}
/// Lit une valeur depuis le stockage sécurisé en fonction de la clé spécifiée.
+ /// Retourne la valeur ou null en cas d'erreur. Chaque action est loguée.
Future read(String key) async {
- print("Lecture dans le stockage sécurisé pour la clé : $key");
- final value = await _storage.read(key: key);
- print("Valeur lue pour la clé $key : $value");
- return value;
+ try {
+ _logger.i("[LOG] Lecture de la clé : $key");
+ final value = await _storage.read(key: key);
+ _logger.i("[LOG] Valeur lue pour la clé $key : $value");
+ return value;
+ } catch (e) {
+ _logger.e("[ERROR] Échec de lecture pour la clé $key : $e");
+ return null;
+ }
}
/// Supprime une entrée dans le stockage sécurisé pour la clé spécifiée.
+ /// Logue chaque étape de l'opération de suppression.
Future delete(String key) async {
- print("Suppression dans le stockage sécurisé pour la clé : $key");
- await _storage.delete(key: key);
- print("Suppression réussie pour la clé : $key");
+ try {
+ _logger.i("[LOG] Suppression de la clé : $key");
+ await _storage.delete(key: key);
+ _logger.i("[LOG] Suppression réussie pour la clé : $key");
+ } catch (e) {
+ _logger.e("[ERROR] Échec de suppression pour la clé $key : $e");
+ rethrow;
+ }
}
/// Sauvegarde l'identifiant utilisateur dans le stockage sécurisé.
+ /// Logue l'action et assure la robustesse de l'opération.
Future saveUserId(String userId) async {
- print("Sauvegarde de l'userId dans le stockage sécurisé : $userId");
- await write('user_id', userId);
- print("Sauvegarde réussie de l'userId.");
+ if (userId.isNotEmpty) {
+ _logger.i("[LOG] Tentative de sauvegarde de l'userId : $userId");
+ await write('user_id', userId);
+ final savedId = await getUserId(); // Récupération immédiate pour vérifier l'enregistrement
+ if (savedId != null && savedId == userId) {
+ _logger.i("[LOG] L'userId a été sauvegardé avec succès et vérifié : $savedId");
+ } else {
+ _logger.e("[ERROR] L'userId n'a pas été correctement sauvegardé.");
+ }
+ } else {
+ _logger.e("[ERROR] L'userId est vide, échec de sauvegarde.");
+ }
}
/// Récupère l'identifiant utilisateur depuis le stockage sécurisé.
+ /// Retourne l'ID ou null en cas d'échec.
Future getUserId() async {
- print("Récupération de l'userId depuis le stockage sécurisé.");
+ _logger.i("[LOG] Récupération de l'userId.");
return await read('user_id');
}
/// Sauvegarde le nom d'utilisateur dans le stockage sécurisé.
- Future saveUserName(String userName) async {
- print("Sauvegarde du userName dans le stockage sécurisé : $userName");
- await write('user_name', userName);
- print("Sauvegarde réussie du userName.");
+ /// Retourne un booléen pour indiquer le succès ou l'échec.
+ Future saveUserName(String userName) async {
+ _logger.i("[LOG] Tentative de sauvegarde du userName : $userName");
+ return await _safeWrite('user_name', userName);
}
/// Récupère le nom d'utilisateur depuis le stockage sécurisé.
+ /// Retourne le nom ou null en cas d'échec.
Future getUserName() async {
- print("Récupération du userName depuis le stockage sécurisé.");
- return await read('user_name');
+ _logger.i("[LOG] Tentative de récupération du userName depuis le stockage sécurisé.");
+ return await _safeRead('user_name');
}
/// Sauvegarde le prénom de l'utilisateur dans le stockage sécurisé.
- Future saveUserLastName(String userLastName) async {
- print("Sauvegarde du userLastName dans le stockage sécurisé : $userLastName");
- await write('user_last_name', userLastName);
- print("Sauvegarde réussie du userLastName.");
+ /// Retourne un booléen pour indiquer le succès ou l'échec.
+ Future saveUserLastName(String userLastName) async {
+ _logger.i("[LOG] Tentative de sauvegarde du userLastName : $userLastName");
+ return await _safeWrite('user_last_name', userLastName);
}
/// Récupère le prénom de l'utilisateur depuis le stockage sécurisé.
+ /// Retourne le prénom ou null en cas d'échec.
Future getUserLastName() async {
- print("Récupération du userLastName depuis le stockage sécurisé.");
- return await read('user_last_name');
+ _logger.i("[LOG] Tentative de récupération du userLastName depuis le stockage sécurisé.");
+ return await _safeRead('user_last_name');
}
/// Supprime toutes les informations utilisateur du stockage sécurisé.
+ /// Logue chaque étape de la suppression.
Future deleteUserInfo() async {
- print("Suppression des informations utilisateur (userId, userName, userLastName).");
+ _logger.i("[LOG] Tentative de suppression de toutes les informations utilisateur.");
await delete('user_id');
await delete('user_name');
await delete('user_last_name');
- print("Suppression réussie des informations utilisateur.");
+ _logger.i("[LOG] Suppression réussie des informations utilisateur.");
+ }
+
+ /// Méthode privée pour encapsuler l'écriture sécurisée avec gestion d'erreur.
+ /// Retourne un booléen indiquant le succès ou l'échec de l'opération.
+ Future _safeWrite(String key, String value) async {
+ try {
+ await write(key, value);
+ return true; // Indique que l'écriture a réussi.
+ } catch (e) {
+ _logger.e("[ERROR] Erreur lors de l'écriture sécurisée : $e");
+ return false; // Indique un échec.
+ }
+ }
+
+ /// Méthode privée pour encapsuler la lecture sécurisée avec gestion d'erreur.
+ /// Retourne la valeur ou null si la lecture échoue.
+ Future _safeRead(String key) async {
+ try {
+ return await read(key);
+ } catch (e) {
+ _logger.e("[ERROR] Erreur lors de la lecture sécurisée : $e");
+ return null; // Retourne null en cas d'erreur.
+ }
}
}
diff --git a/lib/domain/entities/friend.dart b/lib/domain/entities/friend.dart
new file mode 100644
index 0000000..d2e4ad8
--- /dev/null
+++ b/lib/domain/entities/friend.dart
@@ -0,0 +1,119 @@
+import 'package:equatable/equatable.dart';
+import 'package:logger/logger.dart';
+
+/// Enumération représentant les différents statuts possibles d'un ami.
+/// Utilisée pour éviter les erreurs de chaîne de caractères et faciliter les comparaisons.
+enum FriendStatus { pending, accepted, blocked, unknown }
+
+/// Classe [Friend] représentant un ami avec ses informations de base.
+/// Cette classe est conçue pour être utilisée dans des applications de haut niveau
+/// avec une gestion robuste des erreurs, des logs avancés, et une immuabilité stricte.
+///
+/// Chaque instance de [Friend] est immuable et toute modification doit passer par [copyWith].
+class Friend extends Equatable {
+ final String friendId; // ID unique de l'ami, requis et non-nullable
+ final String firstName; // Prénom de l'ami, non-nullable pour garantir une intégrité des données
+ final String lastName; // Nom de famille, non-nullable
+ final String? email; // Adresse e-mail, optionnelle mais typiquement présente
+ final String? imageUrl; // URL de l'image de profil, optionnelle
+ final FriendStatus status; // Statut de l'ami, avec une valeur par défaut `unknown`
+
+ /// Logger statique pour suivre toutes les actions et transformations liées à [Friend].
+ static final Logger _logger = Logger();
+
+ /// Constructeur de la classe [Friend].
+ /// Initialisation avec des valeurs spécifiques pour `firstName` et `lastName`.
+ /// La validation des valeurs est incluse pour garantir l'intégrité des données.
+ Friend({
+ required this.friendId,
+ this.firstName = 'Ami inconnu', // Valeur par défaut pour éviter les champs vides
+ this.lastName = '',
+ this.email,
+ this.imageUrl,
+ this.status = FriendStatus.unknown,
+ }) {
+ assert(friendId.isNotEmpty, 'friendId ne doit pas être vide');
+ _logger.i('[LOG] Création d\'un objet Friend : ID = $friendId, Nom = $firstName $lastName');
+ }
+
+ /// Méthode factory pour créer un objet [Friend] à partir d'un JSON.
+ /// Inclut une validation approfondie pour vérifier l'intégrité des données.
+ ///
+ /// Retourne une instance de [Friend] ou null si les données sont incomplètes.
+ factory Friend.fromJson(Map json) {
+ _logger.i('[LOG] Conversion JSON -> Friend : $json');
+
+ if (json['friendId'] == null || (json['friendId'] as String).isEmpty) {
+ _logger.e('[ERROR] friendId manquant ou vide dans le JSON.');
+ throw ArgumentError("friendId est requis pour créer un objet Friend");
+ }
+
+ return Friend(
+ friendId: json['friendId'] as String,
+ firstName: json['friendFirstName'] as String? ?? 'Ami inconnu',
+ lastName: json['friendLastName'] as String? ?? '',
+ email: json['email'] as String?,
+ imageUrl: json['imageUrl'] as String?,
+ status: _parseStatus(json['status'] as String?),
+ );
+ }
+
+ /// Méthode privée pour parser le champ `status` en type [FriendStatus].
+ /// Retourne [FriendStatus.unknown] si le statut est non reconnu.
+ static FriendStatus _parseStatus(String? status) {
+ switch (status?.toLowerCase()) {
+ case 'pending':
+ return FriendStatus.pending;
+ case 'accepted':
+ return FriendStatus.accepted;
+ case 'blocked':
+ return FriendStatus.blocked;
+ default:
+ return FriendStatus.unknown;
+ }
+ }
+
+ /// Sérialise un objet [Friend] en JSON pour être transmis à l'API.
+ /// Les logs incluent le temps de traitement pour les optimisations de performance.
+ Map toJson() {
+ final json = {
+ 'friendId': friendId,
+ 'firstName': firstName,
+ 'lastName': lastName,
+ 'email': email,
+ 'imageUrl': imageUrl,
+ 'status': status.name,
+ };
+ _logger.i('[LOG] Conversion Friend -> JSON : $json');
+ return json;
+ }
+
+ /// Méthode [copyWith] pour cloner un objet `Friend` en modifiant certains attributs.
+ /// Facilite la modification immuable des propriétés sans affecter l'instance actuelle.
+ ///
+ /// Log chaque copie pour surveiller l'état des données.
+ Friend copyWith({
+ String? friendId,
+ String? firstName,
+ String? lastName,
+ String? email,
+ String? imageUrl,
+ FriendStatus? status,
+ }) {
+ final newFriend = Friend(
+ friendId: friendId ?? this.friendId,
+ firstName: firstName ?? this.firstName,
+ lastName: lastName ?? this.lastName,
+ email: email ?? this.email,
+ imageUrl: imageUrl ?? this.imageUrl,
+ status: status ?? this.status,
+ );
+ _logger.i('[LOG] Création d\'une copie modifiée de Friend : ID = ${newFriend.friendId}');
+ return newFriend;
+ }
+
+ /// Propriétés utilisées pour comparer les objets [Friend],
+ /// facilitant l'utilisation dans des listes et des ensembles.
+ @override
+ List