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:
@@ -7,6 +7,11 @@ import '../../domain/entities/friend.dart';
|
||||
/// et une option pour envoyer un message.
|
||||
/// Utilisé lorsque l'utilisateur clique sur un ami pour voir plus de détails.
|
||||
class FriendDetailScreen extends StatelessWidget {
|
||||
|
||||
/// Constructeur de la classe [FriendDetailScreen].
|
||||
FriendDetailScreen({
|
||||
required this.friendFirstName, required this.friendLastName, required this.imageUrl, required this.friendId, required this.status, required this.lastInteraction, required this.dateAdded, super.key,
|
||||
});
|
||||
final String friendFirstName; // Nom de l'ami
|
||||
final String friendLastName;
|
||||
final String imageUrl; // URL de l'image de profil de l'ami
|
||||
@@ -16,18 +21,6 @@ class FriendDetailScreen extends StatelessWidget {
|
||||
final String lastInteraction;
|
||||
final String dateAdded;
|
||||
|
||||
/// Constructeur de la classe [FriendDetailScreen].
|
||||
FriendDetailScreen({
|
||||
Key? key,
|
||||
required this.friendFirstName,
|
||||
required this.friendLastName,
|
||||
required this.imageUrl,
|
||||
required this.friendId,
|
||||
required this.status,
|
||||
required this.lastInteraction,
|
||||
required this.dateAdded,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Méthode statique pour lancer l'écran des détails d'un ami.
|
||||
static void open(
|
||||
BuildContext context,
|
||||
@@ -37,7 +30,7 @@ class FriendDetailScreen extends StatelessWidget {
|
||||
String imageUrl,
|
||||
FriendStatus status,
|
||||
String lastInteraction,
|
||||
String dateAdded) {
|
||||
String dateAdded,) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -54,16 +47,44 @@ class FriendDetailScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// Vérifie si une URL est valide pour le chargement d'image réseau.
|
||||
bool _isValidImageUrl(String? url) {
|
||||
if (url == null || url.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final uri = Uri.tryParse(url);
|
||||
if (uri == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vérifier que c'est une URL HTTP/HTTPS valide
|
||||
if (!uri.hasScheme || (!uri.scheme.startsWith('http'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vérifier qu'il y a un host
|
||||
if (uri.host.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_logger.i('[LOG] Affichage des détails de l\'ami : $friendFirstName (ID: $friendId)');
|
||||
|
||||
// Utilise `AssetImage` si `imageUrl` est vide ou ne contient pas d'URL valide.
|
||||
final imageProvider =
|
||||
imageUrl.isNotEmpty && Uri.tryParse(imageUrl)?.hasAbsolutePath == true
|
||||
// Vérifier si l'URL est valide avant de créer le NetworkImage
|
||||
final bool hasValidImageUrl = _isValidImageUrl(imageUrl);
|
||||
final ImageProvider imageProvider = hasValidImageUrl
|
||||
? NetworkImage(imageUrl)
|
||||
: const AssetImage('lib/assets/images/default_avatar.png')
|
||||
as ImageProvider;
|
||||
as ImageProvider;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
@@ -72,10 +93,9 @@ class FriendDetailScreen extends StatelessWidget {
|
||||
elevation: 6, // Ombre sous l'app bar pour plus de profondeur
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0), // Espacement autour du contenu
|
||||
padding: const EdgeInsets.all(16), // Espacement autour du contenu
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// Animation Hero pour une transition fluide lors de la navigation
|
||||
Hero(
|
||||
@@ -85,12 +105,12 @@ class FriendDetailScreen extends StatelessWidget {
|
||||
curve: Curves.easeInOut,
|
||||
child: CircleAvatar(
|
||||
radius: 80,
|
||||
backgroundImage: imageProvider,
|
||||
backgroundImage: hasValidImageUrl ? imageProvider : null,
|
||||
backgroundColor: Colors.grey.shade800,
|
||||
onBackgroundImageError: (error, stackTrace) {
|
||||
_logger.e('[ERROR] Erreur lors du chargement de l\'image pour $friendFirstName (ID: $friendId): $error');
|
||||
},
|
||||
child: imageUrl.isEmpty
|
||||
child: !hasValidImageUrl
|
||||
? const Icon(Icons.person, size: 60, color: Colors.white)
|
||||
: null,
|
||||
),
|
||||
@@ -156,9 +176,8 @@ class FriendDetailScreen extends StatelessWidget {
|
||||
/// Widget réutilisable pour afficher une ligne d'information avec un texte d'introduction et une valeur.
|
||||
Widget _buildInfoRow(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12.0),
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
|
||||
Reference in New Issue
Block a user