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

@@ -0,0 +1,114 @@
import 'package:flutter/material.dart';
import '../../domain/entities/friend_request.dart';
/// Widget pour afficher une demande d'amitié en attente.
/// Permet d'accepter ou de rejeter la demande (reçue) ou d'annuler (envoyée).
class FriendRequestCard extends StatelessWidget {
const FriendRequestCard({
required this.request,
required this.onAccept,
required this.onReject,
this.isSentRequest = false,
super.key,
});
final FriendRequest request;
final VoidCallback? onAccept;
final VoidCallback onReject;
final bool isSentRequest;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
// Avatar
CircleAvatar(
radius: 28,
backgroundColor: theme.colorScheme.primaryContainer,
child: Text(
(isSentRequest ? request.friendFullName : request.userFullName).isNotEmpty
? (isSentRequest ? request.friendFullName : request.userFullName)[0].toUpperCase()
: '?',
style: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 16),
// Informations
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isSentRequest
? (request.friendFullName.isNotEmpty
? request.friendFullName
: 'Utilisateur inconnu')
: (request.userFullName.isNotEmpty
? request.userFullName
: 'Utilisateur inconnu'),
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
isSentRequest
? 'Demande envoyée'
: 'Demande d\'amitié',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.6),
),
),
],
),
),
// Boutons d'action
if (isSentRequest)
// Pour les demandes envoyées : seulement bouton Annuler
IconButton(
icon: const Icon(Icons.close),
color: Colors.orange,
onPressed: onReject,
tooltip: 'Annuler la demande',
)
else
// Pour les demandes reçues : Accepter et Rejeter
Row(
mainAxisSize: MainAxisSize.min,
children: [
// Bouton Accepter
IconButton(
icon: const Icon(Icons.check_circle),
color: Colors.green,
onPressed: onAccept,
tooltip: 'Accepter',
),
// Bouton Rejeter
IconButton(
icon: const Icon(Icons.cancel),
color: Colors.red,
onPressed: onReject,
tooltip: 'Rejeter',
),
],
),
],
),
),
);
}
}