import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../../data/providers/friends_provider.dart'; import '../../../domain/entities/friend.dart'; import '../../widgets/friend_detail_screen.dart'; import '../../widgets/search_friends.dart'; /// [FriendsScreen] est l'écran principal permettant d'afficher et de gérer la liste des amis. /// Il inclut des fonctionnalités de pagination, de recherche, et de rafraîchissement manuel de la liste. /// Ce widget est un [StatefulWidget] afin de pouvoir mettre à jour dynamiquement la liste des amis. class FriendsScreen extends StatefulWidget { final String userId; // Identifiant de l'utilisateur pour récupérer ses amis const FriendsScreen({Key? key, required this.userId}) : super(key: key); @override _FriendsScreenState createState() => _FriendsScreenState(); } class _FriendsScreenState extends State { late ScrollController _scrollController; @override void initState() { super.initState(); // Initialisation du contrôleur de défilement pour la gestion de la pagination. _scrollController = ScrollController(); _scrollController.addListener(_onScroll); // Log pour indiquer le début du chargement des amis debugPrint("[LOG] Initialisation de la page : chargement des amis pour l'utilisateur ${widget.userId}"); // Chargement initial de la liste d'amis via le fournisseur (Provider) Provider.of(context, listen: false).fetchFriends(widget.userId); } @override void dispose() { // Nettoyage du contrôleur de défilement pour éviter les fuites de mémoire. _scrollController.removeListener(_onScroll); _scrollController.dispose(); super.dispose(); debugPrint("[LOG] Dispose : contrôleur de défilement supprimé"); } /// Méthode déclenchée lors du défilement de la liste. /// Vérifie si l'utilisateur a atteint le bas de la liste pour charger plus d'amis. void _onScroll() { final provider = Provider.of(context, listen: false); // Ajout d'une marge de 200 pixels pour détecter le bas de la liste plus tôt. if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200 && !provider.isLoading && provider.hasMore) { debugPrint("[LOG] Scroll : Fin de liste atteinte, chargement de la page suivante."); provider.fetchFriends(widget.userId, loadMore: true); // Chargement de plus d'amis } } @override Widget build(BuildContext context) { // Accès au fournisseur pour gérer les données et les états des amis. final friendsProvider = Provider.of(context, listen: false); return Scaffold( appBar: AppBar( title: const Text('Mes Amis'), actions: [ // Bouton pour rafraîchir la liste des amis IconButton( icon: const Icon(Icons.refresh), onPressed: () { // Vérifie si la liste n'est pas en cours de chargement avant d'envoyer une nouvelle requête. if (!friendsProvider.isLoading) { debugPrint("[LOG] Bouton Refresh : demande de rafraîchissement de la liste des amis"); friendsProvider.fetchFriends(widget.userId); } else { debugPrint("[LOG] Rafraîchissement en cours, action ignorée."); } }, ), ], ), body: SafeArea( child: Column( children: [ // Widget de recherche d'amis en haut de l'écran const Padding( padding: EdgeInsets.all(8.0), child: SearchFriends(), ), Expanded( // Construction de la liste d'amis avec un affichage en grille child: Consumer( builder: (context, friendsProvider, child) { // Si le chargement est en cours et qu'il n'y a aucun ami, afficher un indicateur de chargement. if (friendsProvider.isLoading && friendsProvider.friendsList.isEmpty) { debugPrint("[LOG] Chargement : affichage de l'indicateur de progression"); return const Center(child: CircularProgressIndicator()); } // Si la liste est vide après le chargement, afficher un message indiquant qu'aucun ami n'a été trouvé. if (friendsProvider.friendsList.isEmpty) { debugPrint("[LOG] Liste vide : Aucun ami trouvé"); return const Center( child: Text('Aucun ami trouvé'), ); } return GridView.builder( controller: _scrollController, // Utilisation du contrôleur pour la pagination gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, // Deux amis par ligne crossAxisSpacing: 10, mainAxisSpacing: 10, childAspectRatio: 0.8, // Ajuste la taille des cartes ), itemCount: friendsProvider.friendsList.length, itemBuilder: (context, index) { final friend = friendsProvider.friendsList[index]; // Affichage de chaque ami dans une carte avec une animation return GestureDetector( onTap: () => _navigateToFriendDetail(context, friend), // Action au clic sur l'avatar child: AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, transform: Matrix4.identity() ..scale(1.05), // Effet de zoom lors du survol child: Card( elevation: 6, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircleAvatar( radius: 50, backgroundImage: friend.imageUrl != null && friend.imageUrl!.isNotEmpty ? (friend.imageUrl!.startsWith('https') // Vérifie si l'image est une URL réseau. ? NetworkImage(friend.imageUrl!) // Charge l'image depuis une URL réseau. : AssetImage(friend.imageUrl!) as ImageProvider) // Sinon, charge depuis les ressources locales. : const AssetImage('lib/assets/images/default_avatar.png'), // Si aucune image, utilise l'image par défaut. ), const SizedBox(height: 10), Text( "${friend.friendFirstName} ${friend.friendLastName}", style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 5), Text( friend.status.name, style: const TextStyle(fontSize: 14), ), const SizedBox(height: 5), Text( friend.lastInteraction ?? 'Aucune interaction récente', style: const TextStyle( fontStyle: FontStyle.italic, fontSize: 12, ), ), ], ), ), ), ); }, ); }, ), ), ], ), ), ); } /// Navigation vers l'écran de détails de l'ami /// Permet de voir les informations complètes d'un ami lorsque l'utilisateur clique sur son avatar. void _navigateToFriendDetail(BuildContext context, Friend friend) { debugPrint("[LOG] Navigation : Détails de l'ami ${friend.friendFirstName} ${friend.friendLastName}"); Navigator.push( context, MaterialPageRoute( builder: (context) => FriendDetailScreen( friendFirstName: friend.friendFirstName, // Prénom de l'ami friendLastName: friend.friendLastName, // Nom de l'ami imageUrl: friend.imageUrl ?? '', // URL de l'image de l'ami (ou valeur par défaut) friendId: friend.friendId, // Identifiant unique de l'ami status: friend.status, // Statut de l'ami lastInteraction: friend.lastInteraction ?? 'Aucune', // Dernière interaction (si disponible) dateAdded: friend.dateAdded ?? 'Inconnu', // Date d'ajout de l'ami (si disponible) ), ), ); } }