import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../../core/constants/design_system.dart'; import '../../../core/utils/page_transitions.dart'; import '../../../data/providers/friends_provider.dart'; import '../../widgets/add_friend_dialog.dart'; import '../../widgets/animated_widgets.dart'; import '../../widgets/custom_snackbar.dart'; import '../../widgets/friends_tab.dart'; import '../../widgets/requests_tab.dart'; /// Écran principal pour afficher et gérer la liste des amis. /// /// Cet écran inclut des fonctionnalités de pagination, de recherche, /// et de rafraîchissement manuel de la liste avec design moderne et compact. /// /// **Fonctionnalités:** /// - Affichage de la liste des amis en grille /// - Recherche d'amis /// - Pagination automatique /// - Pull-to-refresh /// - Ajout d'amis /// - Gestion des demandes d'amitié (reçues et envoyées) class FriendsScreen extends StatefulWidget { const FriendsScreen({required this.userId, super.key}); final String userId; @override State createState() => _FriendsScreenState(); } class _FriendsScreenState extends State with SingleTickerProviderStateMixin { // ============================================================================ // CONSTANTS // ============================================================================ static const double _scrollThreshold = 200; static const Duration _refreshDelay = Duration(milliseconds: 500); // ============================================================================ // CONTROLLERS // ============================================================================ late final ScrollController _scrollController; late final TabController _tabController; // ============================================================================ // LIFECYCLE // ============================================================================ @override void initState() { super.initState(); _initializeControllers(); _loadInitialData(); } @override void dispose() { _disposeControllers(); super.dispose(); } // ============================================================================ // INITIALIZATION // ============================================================================ /// Initialise les contrôleurs. void _initializeControllers() { _scrollController = ScrollController()..addListener(_onScroll); _tabController = TabController(length: 2, vsync: this); } /// Libère les ressources des contrôleurs. void _disposeControllers() { _scrollController ..removeListener(_onScroll) ..dispose(); _tabController.dispose(); } /// Charge les données initiales. void _loadInitialData() { final provider = Provider.of(context, listen: false); provider ..fetchFriends(widget.userId) ..fetchSentRequests() ..fetchReceivedRequests(); } // ============================================================================ // SCROLL HANDLING // ============================================================================ /// Gère le défilement pour la pagination. void _onScroll() { final provider = Provider.of(context, listen: false); if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - _scrollThreshold && !provider.isLoading && provider.hasMore) { provider.fetchFriends(widget.userId, loadMore: true); } } // ============================================================================ // ACTIONS // ============================================================================ /// Gère le rafraîchissement de la liste des amis. Future _handleRefresh() async { final provider = Provider.of(context, listen: false); provider.fetchFriends(widget.userId); await Future.delayed(_refreshDelay); } /// Gère l'ajout d'un ami. void _handleAddFriend() { showDialog( context: context, builder: (context) => AddFriendDialog( onFriendAdded: _onFriendAdded, ), ); } /// Callback appelé après l'ajout d'un ami. void _onFriendAdded() { final provider = Provider.of(context, listen: false); provider ..fetchFriends(widget.userId) ..fetchSentRequests() ..fetchReceivedRequests(); } /// Gère l'actualisation manuelle. void _handleRefreshAll() { final provider = Provider.of(context, listen: false); provider ..fetchFriends(widget.userId) ..fetchSentRequests() ..fetchReceivedRequests(); } // ============================================================================ // BUILD // ============================================================================ @override Widget build(BuildContext context) { return Scaffold( appBar: _buildAppBar(), body: _buildBody(), floatingActionButton: _buildFloatingActionButton(), ); } /// Construit la barre d'application. PreferredSizeWidget _buildAppBar() { final theme = Theme.of(context); return AppBar( elevation: 0, scrolledUnderElevation: 2, title: Text( 'Mes Amis', style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.bold, letterSpacing: -0.5, ), ), bottom: TabBar( controller: _tabController, indicatorSize: TabBarIndicatorSize.tab, tabs: const [ Tab( text: 'Amis', icon: Icon(Icons.people_rounded, size: 22), iconMargin: EdgeInsets.only(bottom: 4), ), Tab( text: 'Demandes', icon: Icon(Icons.person_add_rounded, size: 22), iconMargin: EdgeInsets.only(bottom: 4), ), ], ), actions: [ IconButton( icon: const Icon(Icons.refresh_rounded, size: 22), tooltip: 'Actualiser', onPressed: _handleRefreshAll, ), ], ); } /// Construit le corps de l'écran. Widget _buildBody() { return SafeArea( child: TabBarView( controller: _tabController, children: [ FriendsTab( userId: widget.userId, scrollController: _scrollController, onRefresh: _handleRefresh, ), RequestsTab( onAccept: _handleAcceptRequest, onReject: _handleRejectRequest, onCancel: _handleCancelRequest, onRefresh: _handleRefreshAll, ), ], ), ); } /// Construit le bouton flottant. Widget _buildFloatingActionButton() { return FloatingActionButton( onPressed: _handleAddFriend, tooltip: 'Ajouter un ami', elevation: 2, child: const Icon(Icons.person_add_rounded, size: 24), ); } // ============================================================================ // REQUEST HANDLERS // ============================================================================ /// Gère l'acceptation d'une demande d'amitié. Future _handleAcceptRequest( FriendsProvider provider, String friendshipId, ) async { try { await provider.acceptFriendRequest(friendshipId); if (!mounted) return; context.showSuccess('Demande d\'amitié acceptée'); _refreshAfterRequest(); } catch (e) { if (!mounted) return; context.showError('Erreur: ${e.toString()}'); } } /// Gère le rejet d'une demande d'amitié. Future _handleRejectRequest( FriendsProvider provider, String friendshipId, ) async { try { await provider.rejectFriendRequest(friendshipId); if (!mounted) return; context.showWarning('Demande d\'amitié rejetée'); provider.fetchReceivedRequests(); } catch (e) { if (!mounted) return; context.showError('Erreur: ${e.toString()}'); } } /// Gère l'annulation d'une demande d'amitié envoyée. Future _handleCancelRequest( FriendsProvider provider, String friendshipId, ) async { try { await provider.cancelFriendRequest(friendshipId); if (!mounted) return; context.showInfo('Demande d\'amitié annulée'); provider.fetchSentRequests(); } catch (e) { if (!mounted) return; context.showError('Erreur: ${e.toString()}'); } } // ============================================================================ // HELPERS // ============================================================================ /// Rafraîchit les données après une action sur une demande. void _refreshAfterRequest() { final provider = Provider.of(context, listen: false); provider ..fetchFriends(widget.userId) ..fetchReceivedRequests(); } }