Refactoring + Checkpoint

This commit is contained in:
DahoudG
2024-11-17 23:00:18 +00:00
parent 1e888f41e8
commit 77ab8a02a2
56 changed files with 1904 additions and 790 deletions

View File

@@ -1,42 +0,0 @@
import 'package:flutter/material.dart';
import '../../widgets/friend_card.dart';
import '../../widgets/friend_detail_screen.dart';
class FriendsContent extends StatelessWidget {
final List<Map<String, String>> friends = [
{'name': 'Alice', 'imageUrl': 'https://example.com/image1.jpg'},
{'name': 'Bob', 'imageUrl': 'https://example.com/image2.jpg'},
{'name': 'Charlie', 'imageUrl': 'https://example.com/image3.jpg'},
// Autres amis...
];
@override
Widget build(BuildContext context) {
return ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0),
itemCount: friends.length,
itemBuilder: (context, index) {
final friend = friends[index];
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: FriendCard(
name: friend['name']!,
imageUrl: friend['imageUrl']!,
onTap: () => _navigateToFriendDetail(context, friend),
),
);
},
);
}
void _navigateToFriendDetail(BuildContext context, Map<String, String> friend) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => FriendDetailScreen(
name: friend['name']!,
imageUrl: friend['imageUrl']!,
friendId: friend['friendId']!,
),
));
}
}

View File

@@ -1,12 +1,13 @@
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/friends_circle.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
@@ -28,7 +29,7 @@ class _FriendsScreenState extends State<FriendsScreen> {
// 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
// Chargement initial de la liste d'amis via le fournisseur (Provider)
Provider.of<FriendsProvider>(context, listen: false).fetchFriends(widget.userId);
}
@@ -46,12 +47,12 @@ class _FriendsScreenState extends State<FriendsScreen> {
void _onScroll() {
final provider = Provider.of<FriendsProvider>(context, listen: false);
// Ajout d'une marge de 200 pixels pour détecter le bas de la liste plus tôt
// 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);
provider.fetchFriends(widget.userId, loadMore: true); // Chargement de plus d'amis
}
}
@@ -64,9 +65,11 @@ class _FriendsScreenState extends State<FriendsScreen> {
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);
@@ -80,13 +83,13 @@ class _FriendsScreenState extends State<FriendsScreen> {
body: SafeArea(
child: Column(
children: [
// Widget de recherche d'amis en haut de l'écran
const Padding(
padding: EdgeInsets.all(8.0),
// Widget pour la recherche d'amis
child: SearchFriends(),
),
Expanded(
// Construction de la liste d'amis basée sur l'état du FriendsProvider
// Construction de la liste d'amis avec un affichage en grille
child: Consumer<FriendsProvider>(
builder: (context, friendsProvider, child) {
// Si le chargement est en cours et qu'il n'y a aucun ami, afficher un indicateur de chargement.
@@ -103,40 +106,69 @@ class _FriendsScreenState extends State<FriendsScreen> {
);
}
// Affichage de la grille des amis
debugPrint("[LOG] Affichage de la grille des amis (nombre d'amis : ${friendsProvider.friendsList.length})");
return GridView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10,
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 + (friendsProvider.isLoading && friendsProvider.hasMore ? 1 : 0),
itemCount: friendsProvider.friendsList.length,
itemBuilder: (context, index) {
if (index >= friendsProvider.friendsList.length) {
return const Center(child: CircularProgressIndicator());
}
final friend = friendsProvider.friendsList[index];
debugPrint("[LOG] Affichage de l'ami à l'index $index avec ID : ${friend.friendId}");
return FriendsCircle(
friend: friend,
onTap: () {
debugPrint("[LOG] Détail : Affichage des détails de l'ami ID : ${friend.friendId}");
FriendDetailScreen.open(
context,
friend.friendId,
friend.friendFirstName,
friend.imageUrl ?? '',
);
},
// 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,
),
),
],
),
),
),
);
},
);
},
),
),
@@ -145,4 +177,24 @@ class _FriendsScreenState extends State<FriendsScreen> {
),
);
}
/// 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)
),
),
);
}
}

View File

@@ -8,20 +8,21 @@ import '../../widgets/friend_detail_screen.dart';
import '../../widgets/friends_appbar.dart';
import '../../widgets/search_friends.dart';
/// Écran d'affichage des amis avec gestion des amis via un provider.
class FriendsScreenWithProvider extends StatelessWidget {
final Logger _logger = Logger(); // Logger pour une meilleure traçabilité
final Logger _logger = Logger(); // Logger pour la traçabilité détaillée.
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: FriendsAppBar(),
backgroundColor: Colors.black, // Fond noir pour une ambiance immersive.
appBar: FriendsAppBar(), // AppBar personnalisé pour l'écran.
body: SafeArea(
child: Column(
children: [
const Padding(
padding: EdgeInsets.all(8.0),
child: SearchFriends(),
child: SearchFriends(), // Barre de recherche pour trouver des amis.
),
Expanded(
child: Consumer<FriendsProvider>(
@@ -29,10 +30,10 @@ class FriendsScreenWithProvider extends StatelessWidget {
final friends = friendsProvider.friendsList;
if (friends.isEmpty) {
_logger.i("[LOG] Aucun ami trouvé");
_logger.i("[LOG] Aucun ami trouvé."); // Log pour la recherche sans résultat.
return const Center(
child: Text(
'Aucun ami trouvé',
'Aucun ami trouvé', // Message affiché si aucun ami n'est trouvé.
style: TextStyle(color: Colors.white70),
),
);
@@ -43,6 +44,10 @@ class FriendsScreenWithProvider extends StatelessWidget {
itemCount: friends.length,
itemBuilder: (context, index) {
final friend = friends[index];
// Log lorsque chaque ami est affiché
_logger.i("[LOG] Affichage de l'ami : ${friend.friendFirstName ?? 'Ami inconnu'}");
return Dismissible(
key: Key(friend.friendId),
background: Container(
@@ -53,7 +58,7 @@ class FriendsScreenWithProvider extends StatelessWidget {
),
onDismissed: (direction) {
_logger.i("[LOG] Suppression de l'ami avec l'ID : ${friend.friendId}");
friendsProvider.removeFriend(friend.friendId);
friendsProvider.removeFriend(friend.friendId); // Suppression de l'ami via le provider.
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Ami supprimé : ${friend.friendFirstName}")),
);
@@ -61,14 +66,16 @@ class FriendsScreenWithProvider extends StatelessWidget {
child: FriendExpandingCard(
name: friend.friendFirstName ?? 'Ami inconnu',
imageUrl: friend.imageUrl ?? '',
description: "Amis depuis ${friend.friendId}",
onTap: () => _navigateToFriendDetail(context, friend),
description: "Amis depuis ${friend.dateAdded ?? 'Inconnu'}\nStatut : ${friend.status ?? 'Inconnu'}",
onTap: () {
_navigateToFriendDetail(context, friend); // Navigation vers les détails de l'ami.
},
onMessageTap: () {
_logger.i("[LOG] Envoi d'un message à l'ami : ${friend.friendFirstName ?? 'Ami inconnu'}");
},
onRemoveTap: () {
_logger.i("[LOG] Tentative de suppression de l'ami : ${friend.friendFirstName ?? 'Ami inconnu'}");
friendsProvider.removeFriend(friend.friendId);
friendsProvider.removeFriend(friend.friendId); // Suppression via le provider.
},
),
);
@@ -83,13 +90,19 @@ class FriendsScreenWithProvider extends StatelessWidget {
);
}
/// Navigue vers l'écran de détails de l'ami.
void _navigateToFriendDetail(BuildContext context, Friend friend) {
_logger.i("[LOG] Navigation vers les détails de l'ami : ${friend.friendFirstName}");
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => FriendDetailScreen(
name: friend.friendFirstName,
imageUrl: friend.imageUrl ?? '',
friendId: friend.friendId,
friendFirstName: friend.friendFirstName,
friendLastName: friend.friendLastName,
imageUrl: friend.imageUrl ?? '',
status: friend.status,
lastInteraction: friend.lastInteraction ?? 'Aucune',
dateAdded: friend.dateAdded ?? 'Inconnu',
),
));
}