feat(frontend): Séparation des demandes d'amitié envoyées et reçues

- Ajout de deux endpoints distincts dans Urls: getSentFriendRequestsWithUserId et getReceivedFriendRequestsWithUserId
- Ajout de méthodes dans FriendsRepository et FriendsRepositoryImpl pour récupérer séparément les demandes envoyées et reçues
- Ajout de la méthode cancelFriendRequest pour annuler une demande envoyée
- Modification de FriendsProvider pour gérer deux listes distinctes: sentRequests et receivedRequests
- Mise à jour de FriendsScreen pour afficher deux sections:
  - Demandes reçues: avec boutons Accepter/Rejeter
  - Demandes envoyées: avec bouton Annuler uniquement
- Correction du mapping JSON dans FriendRequest.fromJson (userNom/userPrenoms correctement mappés)
- Amélioration de FriendRequestCard pour gérer les deux types de demandes
- Correction de la validation d'URL d'image dans FriendDetailScreen
- Support du champ uuid dans UserModel.fromJson pour compatibilité backend
This commit is contained in:
dahoud
2026-01-07 16:33:27 +00:00
parent 69c8c21591
commit 06031b01f2
10 changed files with 2599 additions and 373 deletions

View File

@@ -1,13 +1,19 @@
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import '../../domain/entities/friend.dart';
import '../../data/repositories/friends_repository_impl.dart';
import '../../data/services/secure_storage.dart';
import '../../domain/entities/friend.dart';
import '../../domain/entities/friend_request.dart';
/// [FriendsProvider] est un `ChangeNotifier` qui gère la logique de gestion des amis.
/// Il interagit avec le [FriendsRepositoryImpl] pour effectuer des appels API et gérer
/// la liste des amis de l'utilisateur, avec une gestion avancée de la pagination,
/// du statut des amis et de la gestion des erreurs.
class FriendsProvider with ChangeNotifier {
class FriendsProvider with ChangeNotifier { // Nombre d'amis à récupérer par page
/// Constructeur de [FriendsProvider] qui nécessite l'instance d'un [FriendsRepositoryImpl].
FriendsProvider({required this.friendsRepository});
final FriendsRepositoryImpl friendsRepository;
final Logger _logger = Logger(); // Utilisation du logger pour une traçabilité complète des actions.
@@ -16,15 +22,32 @@ class FriendsProvider with ChangeNotifier {
bool _isLoading = false; // Indicateur de chargement
bool _hasMore = true; // Indicateur de pagination
int _currentPage = 0; // Numéro de la page actuelle pour la pagination
final int _friendsPerPage = 10; // Nombre d'amis à récupérer par page
final int _friendsPerPage = 10;
/// Constructeur de [FriendsProvider] qui nécessite l'instance d'un [FriendsRepositoryImpl].
FriendsProvider({required this.friendsRepository});
// Liste des demandes d'amitié envoyées
List<FriendRequest> _sentRequests = [];
bool _isLoadingSentRequests = false;
int _currentSentRequestPage = 0;
// Liste des demandes d'amitié reçues
List<FriendRequest> _receivedRequests = [];
bool _isLoadingReceivedRequests = false;
int _currentReceivedRequestPage = 0;
final int _requestsPerPage = 10;
// Getters pour accéder à l'état actuel des données
bool get isLoading => _isLoading;
bool get hasMore => _hasMore;
List<Friend> get friendsList => _friendsList;
List<FriendRequest> get sentRequests => _sentRequests;
List<FriendRequest> get receivedRequests => _receivedRequests;
bool get isLoadingSentRequests => _isLoadingSentRequests;
bool get isLoadingReceivedRequests => _isLoadingReceivedRequests;
// Pour compatibilité avec l'ancien code
List<FriendRequest> get pendingRequests => _receivedRequests;
bool get isLoadingRequests => _isLoadingReceivedRequests;
/// Récupère la liste des amis pour un utilisateur donné avec pagination.
///
@@ -63,10 +86,10 @@ class FriendsProvider with ChangeNotifier {
_logger.i('[LOG] Plus d\'amis à charger.');
} else {
// Ajout des amis à la liste, en excluant l'utilisateur connecté
for (var friend in newFriends) {
for (final friend in newFriends) {
if (friend.friendId != userId) {
_friendsList.add(friend);
_logger.i("[LOG] Ami ajouté : ID = ${friend.friendId}, Nom = ${friend.friendFirstName} ${friend.friendLastName}");
_logger.i('[LOG] Ami ajouté : ID = ${friend.friendId}, Nom = ${friend.friendFirstName} ${friend.friendLastName}');
} else {
_logger.w("[WARN] L'utilisateur connecté est exclu de la liste des amis : ${friend.friendId}");
}
@@ -171,4 +194,192 @@ class FriendsProvider with ChangeNotifier {
notifyListeners();
}
}
/// Ajoute un nouvel ami.
///
/// [friendId] : L'identifiant unique de l'ami à ajouter.
///
/// Cette méthode :
/// - Loggue chaque étape.
/// - Envoie la demande d'ami via l'API.
/// - Rafraîchit la liste des amis si l'ajout réussit.
Future<void> addFriend(String friendId) async {
try {
// Récupérer le userId de l'utilisateur actuel
final currentUserId = await _getCurrentUserId();
if (currentUserId == null || currentUserId.isEmpty) {
throw Exception('Utilisateur non connecté');
}
_logger.i('[LOG] Ajout de l\'ami: userId=$currentUserId, friendId=$friendId');
await friendsRepository.addFriend(currentUserId, friendId);
_logger.i('[LOG] Demande d\'ami envoyée avec succès');
// Rafraîchir la liste des amis après l'ajout
// Note: L'ami ne sera visible qu'après acceptation de la demande
} catch (e) {
_logger.e('[ERROR] Erreur lors de l\'ajout de l\'ami : $e');
rethrow; // Propager l'erreur pour que l'UI puisse l'afficher
} finally {
notifyListeners();
}
}
/// Récupère l'ID de l'utilisateur actuel depuis le stockage sécurisé
Future<String?> _getCurrentUserId() async {
try {
final secureStorage = SecureStorage();
return await secureStorage.getUserId();
} catch (e) {
_logger.e('[ERROR] Erreur lors de la récupération de l\'userId : $e');
return null;
}
}
/// Récupère les demandes d'amitié en attente pour l'utilisateur actuel (compatibilité).
Future<void> fetchPendingRequests({bool loadMore = false}) async {
await fetchReceivedRequests(loadMore: loadMore);
}
/// Récupère les demandes d'amitié envoyées par l'utilisateur actuel.
Future<void> fetchSentRequests({bool loadMore = false}) async {
try {
final currentUserId = await _getCurrentUserId();
if (currentUserId == null || currentUserId.isEmpty) {
throw Exception('Utilisateur non connecté');
}
if (!loadMore) {
_currentSentRequestPage = 0;
_sentRequests = [];
}
_isLoadingSentRequests = true;
notifyListeners();
final page = loadMore ? _currentSentRequestPage + 1 : 0;
final requests = await friendsRepository.getSentFriendRequests(
currentUserId,
page,
_requestsPerPage,
);
if (loadMore) {
_sentRequests.addAll(requests);
_currentSentRequestPage = page;
} else {
_sentRequests = requests;
_currentSentRequestPage = 0;
}
_logger.i('[LOG] ${requests.length} demandes d\'amitié envoyées récupérées');
} catch (e) {
_logger.e('[ERROR] Erreur lors de la récupération des demandes envoyées : $e');
rethrow;
} finally {
_isLoadingSentRequests = false;
notifyListeners();
}
}
/// Récupère les demandes d'amitié reçues par l'utilisateur actuel.
Future<void> fetchReceivedRequests({bool loadMore = false}) async {
try {
final currentUserId = await _getCurrentUserId();
if (currentUserId == null || currentUserId.isEmpty) {
throw Exception('Utilisateur non connecté');
}
if (!loadMore) {
_currentReceivedRequestPage = 0;
_receivedRequests = [];
}
_isLoadingReceivedRequests = true;
notifyListeners();
final page = loadMore ? _currentReceivedRequestPage + 1 : 0;
final requests = await friendsRepository.getReceivedFriendRequests(
currentUserId,
page,
_requestsPerPage,
);
if (loadMore) {
_receivedRequests.addAll(requests);
_currentReceivedRequestPage = page;
} else {
_receivedRequests = requests;
_currentReceivedRequestPage = 0;
}
_logger.i('[LOG] ${requests.length} demandes d\'amitié reçues récupérées');
} catch (e) {
_logger.e('[ERROR] Erreur lors de la récupération des demandes reçues : $e');
rethrow;
} finally {
_isLoadingReceivedRequests = false;
notifyListeners();
}
}
/// Accepte une demande d'amitié.
Future<void> acceptFriendRequest(String friendshipId) async {
try {
_logger.i('[LOG] Acceptation de la demande d\'amitié: $friendshipId');
await friendsRepository.acceptFriendRequest(friendshipId);
// Retirer la demande de la liste des demandes reçues
_receivedRequests.removeWhere((req) => req.friendshipId == friendshipId);
// Rafraîchir la liste des amis
final currentUserId = await _getCurrentUserId();
if (currentUserId != null) {
await fetchFriends(currentUserId);
}
_logger.i('[LOG] Demande d\'amitié acceptée avec succès');
} catch (e) {
_logger.e('[ERROR] Erreur lors de l\'acceptation de la demande : $e');
rethrow;
} finally {
notifyListeners();
}
}
/// Rejette une demande d'amitié.
Future<void> rejectFriendRequest(String friendshipId) async {
try {
_logger.i('[LOG] Rejet de la demande d\'amitié: $friendshipId');
await friendsRepository.rejectFriendRequest(friendshipId);
// Retirer la demande de la liste des demandes reçues
_receivedRequests.removeWhere((req) => req.friendshipId == friendshipId);
_logger.i('[LOG] Demande d\'amitié rejetée avec succès');
} catch (e) {
_logger.e('[ERROR] Erreur lors du rejet de la demande : $e');
rethrow;
} finally {
notifyListeners();
}
}
/// Annule une demande d'amitié envoyée.
Future<void> cancelFriendRequest(String friendshipId) async {
try {
_logger.i('[LOG] Annulation de la demande d\'amitié: $friendshipId');
await friendsRepository.cancelFriendRequest(friendshipId);
// Retirer la demande de la liste des demandes envoyées
_sentRequests.removeWhere((req) => req.friendshipId == friendshipId);
_logger.i('[LOG] Demande d\'amitié annulée avec succès');
} catch (e) {
_logger.e('[ERROR] Erreur lors de l\'annulation de la demande : $e');
rethrow;
} finally {
notifyListeners();
}
}
}