Refactoring
This commit is contained in:
68
lib/assets/json/event_categories.json
Normal file
68
lib/assets/json/event_categories.json
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"categories": {
|
||||||
|
"Événements Professionnels": [
|
||||||
|
"Conférence",
|
||||||
|
"Séminaire",
|
||||||
|
"Webinar",
|
||||||
|
"Atelier",
|
||||||
|
"Networking",
|
||||||
|
"Réunion d'affaires",
|
||||||
|
"Salon",
|
||||||
|
"Forum",
|
||||||
|
"Rencontre professionnelle",
|
||||||
|
"Conférence académique",
|
||||||
|
"Conférence TEDx",
|
||||||
|
"Lancement de produit",
|
||||||
|
"Assemblée générale",
|
||||||
|
"Réunion de crise",
|
||||||
|
"Lancement de startup"
|
||||||
|
],
|
||||||
|
"Événements Culturels": [
|
||||||
|
"Concert",
|
||||||
|
"Festival",
|
||||||
|
"Exposition",
|
||||||
|
"Projection de film",
|
||||||
|
"Rencontre littéraire",
|
||||||
|
"Spectacle de théâtre",
|
||||||
|
"Spectacle de danse",
|
||||||
|
"Festival de cinéma",
|
||||||
|
"Exposition d'art",
|
||||||
|
"Projection en avant-première",
|
||||||
|
"Festival de bande dessinée",
|
||||||
|
"Projection de documentaire",
|
||||||
|
"Festival de rue"
|
||||||
|
],
|
||||||
|
"Événements Sportifs": [
|
||||||
|
"Compétition sportive",
|
||||||
|
"Marathon",
|
||||||
|
"Tournoi de jeux vidéo",
|
||||||
|
"Hackathon",
|
||||||
|
"Compétition de sport électronique",
|
||||||
|
"Tournoi sportif"
|
||||||
|
],
|
||||||
|
"Événements Caritatifs": [
|
||||||
|
"Dîner caritatif",
|
||||||
|
"Collecte de fonds",
|
||||||
|
"Vente aux enchères",
|
||||||
|
"Vente de charité"
|
||||||
|
],
|
||||||
|
"Événements Sociaux": [
|
||||||
|
"Fête nationale",
|
||||||
|
"Fête de mariage",
|
||||||
|
"Anniversaire",
|
||||||
|
"Réveillon du nouvel an",
|
||||||
|
"Fête de Noël",
|
||||||
|
"Soirée de gala",
|
||||||
|
"Fête de fin d'année"
|
||||||
|
],
|
||||||
|
"Ateliers et Formations": [
|
||||||
|
"Atelier culinaire",
|
||||||
|
"Cours de yoga",
|
||||||
|
"Session de formation",
|
||||||
|
"Atelier de design",
|
||||||
|
"Atelier d'écriture",
|
||||||
|
"Atelier de peinture",
|
||||||
|
"Atelier de bricolage"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
32
lib/data/services/category_service.dart
Normal file
32
lib/data/services/category_service.dart
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
/// Service pour gérer le chargement des catégories depuis un fichier JSON.
|
||||||
|
class CategoryService {
|
||||||
|
/// Méthode pour charger les catégories depuis un fichier JSON.
|
||||||
|
/// Cette méthode retourne un Map où chaque clé représente un type de catégorie
|
||||||
|
/// et chaque valeur est une liste de catégories associées à ce type.
|
||||||
|
Future<Map<String, List<String>>> loadCategories() async {
|
||||||
|
try {
|
||||||
|
// Charger le fichier JSON à partir des assets
|
||||||
|
print('Chargement du fichier JSON des catégories...');
|
||||||
|
final String response = await rootBundle.loadString('lib/assets/json/event_categories.json');
|
||||||
|
|
||||||
|
// Décoder le contenu du fichier JSON
|
||||||
|
final Map<String, dynamic> data = json.decode(response);
|
||||||
|
print('Données JSON décodées avec succès.');
|
||||||
|
|
||||||
|
// Transformer les données en un Map de catégories par type
|
||||||
|
final Map<String, List<String>> categoriesByType = (data['categories'] as Map<String, dynamic>).map(
|
||||||
|
(key, value) => MapEntry(key, List<String>.from(value)),
|
||||||
|
);
|
||||||
|
|
||||||
|
print('Catégories chargées: $categoriesByType');
|
||||||
|
return categoriesByType;
|
||||||
|
} catch (e) {
|
||||||
|
// Gérer les erreurs de chargement ou de décodage
|
||||||
|
print('Erreur lors du chargement des catégories: $e');
|
||||||
|
throw Exception('Impossible de charger les catégories.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'package:afterwork/data/models/event_model.dart';
|
import 'package:afterwork/data/models/event_model.dart';
|
||||||
import 'package:afterwork/data/models/user_model.dart';
|
import 'package:afterwork/data/models/user_model.dart';
|
||||||
import 'package:afterwork/core/constants/urls.dart';
|
import 'package:afterwork/core/constants/urls.dart';
|
||||||
|
import 'package:afterwork/data/services/category_service.dart';
|
||||||
import '../location/location_picker_screen.dart';
|
import '../location/location_picker_screen.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
/// Classe représentant la boîte de dialogue pour ajouter un nouvel événement.
|
/// Classe représentant la boîte de dialogue pour ajouter un nouvel événement.
|
||||||
/// Cette boîte de dialogue permet à l'utilisateur de remplir les détails d'un nouvel événement.
|
|
||||||
class AddEventDialog extends StatefulWidget {
|
class AddEventDialog extends StatefulWidget {
|
||||||
final String userId;
|
final String userId;
|
||||||
final String userName;
|
final String userName;
|
||||||
@@ -27,15 +27,36 @@ class AddEventDialog extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AddEventDialogState extends State<AddEventDialog> {
|
class _AddEventDialogState extends State<AddEventDialog> {
|
||||||
final _formKey = GlobalKey<FormState>(); // Clé globale pour valider le formulaire
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
// Variables pour stocker les données de l'événement
|
||||||
String _title = '';
|
String _title = '';
|
||||||
String _description = '';
|
String _description = '';
|
||||||
DateTime? _selectedDate;
|
DateTime? _selectedDate;
|
||||||
String? _imagePath;
|
String? _imagePath;
|
||||||
String _location = 'Abidjan'; // Par défaut à Cocody, Abidjan
|
String _location = 'Abidjan';
|
||||||
String _category = '';
|
String _category = '';
|
||||||
String _link = '';
|
String _link = '';
|
||||||
LatLng? _selectedLatLng = const LatLng(5.348722, -3.985038); // Par défaut à Cocody, Abidjan
|
LatLng? _selectedLatLng = const LatLng(5.348722, -3.985038);
|
||||||
|
Map<String, List<String>> _categories = {};
|
||||||
|
List<String> _currentCategories = [];
|
||||||
|
String? _selectedCategoryType;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loadCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _loadCategories() async {
|
||||||
|
final CategoryService categoryService = CategoryService();
|
||||||
|
final categories = await categoryService.loadCategories();
|
||||||
|
setState(() {
|
||||||
|
_categories = categories;
|
||||||
|
_selectedCategoryType = categories.keys.first;
|
||||||
|
_currentCategories = categories[_selectedCategoryType] ?? [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -48,7 +69,7 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey, // Formulaire clé pour valider l'entrée des utilisateurs
|
key: _formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -75,7 +96,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construction du champ de saisie du titre de l'événement.
|
|
||||||
Widget _buildTitleField() {
|
Widget _buildTitleField() {
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -104,7 +124,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construction du champ de saisie de la description de l'événement.
|
|
||||||
Widget _buildDescriptionField() {
|
Widget _buildDescriptionField() {
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -134,7 +153,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Widget pour le sélecteur de date pour l'événement.
|
|
||||||
Widget _buildDatePicker() {
|
Widget _buildDatePicker() {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -175,7 +193,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construction du champ de localisation pour l'événement.
|
|
||||||
Widget _buildLocationField(BuildContext context) {
|
Widget _buildLocationField(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -217,29 +234,76 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construction du champ de saisie de la catégorie de l'événement.
|
/// Construction du champ de catégorie avec sélection du type et de la catégorie.
|
||||||
Widget _buildCategoryField() {
|
Widget _buildCategoryField() {
|
||||||
return TextFormField(
|
return Column(
|
||||||
decoration: InputDecoration(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
labelText: 'Catégorie',
|
children: [
|
||||||
labelStyle: const TextStyle(color: Colors.white70),
|
DropdownButtonFormField<String>(
|
||||||
filled: true,
|
decoration: InputDecoration(
|
||||||
fillColor: Colors.white.withOpacity(0.1),
|
labelText: 'Type de catégorie',
|
||||||
border: const OutlineInputBorder(
|
labelStyle: const TextStyle(color: Colors.white70),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
filled: true,
|
||||||
borderSide: BorderSide.none,
|
fillColor: Colors.white.withOpacity(0.1),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||||
|
borderSide: BorderSide.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
value: _selectedCategoryType,
|
||||||
|
items: _categories.keys.map((String type) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: type,
|
||||||
|
child: Text(type, style: const TextStyle(color: Colors.black)),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
_selectedCategoryType = newValue;
|
||||||
|
_currentCategories = _categories[newValue] ?? [];
|
||||||
|
_category = ''; // Réinitialiser la catégorie sélectionnée
|
||||||
|
print('Type de catégorie sélectionné : $_selectedCategoryType');
|
||||||
|
print('Catégories disponibles pour ce type : $_currentCategories');
|
||||||
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
prefixIcon: const Icon(Icons.category, color: Colors.white70),
|
const SizedBox(height: 10),
|
||||||
),
|
DropdownButtonFormField<String>(
|
||||||
style: const TextStyle(color: Colors.white),
|
decoration: InputDecoration(
|
||||||
onSaved: (value) {
|
labelText: 'Catégorie',
|
||||||
_category = value ?? '';
|
labelStyle: const TextStyle(color: Colors.white70),
|
||||||
print('Catégorie sauvegardée: $_category');
|
filled: true,
|
||||||
},
|
fillColor: Colors.white.withOpacity(0.1),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||||
|
borderSide: BorderSide.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
value: _category.isNotEmpty ? _category : null,
|
||||||
|
items: _currentCategories.map((String category) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: category,
|
||||||
|
child: Text(category, style: const TextStyle(color: Colors.black)),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
_category = newValue ?? '';
|
||||||
|
print('Catégorie sélectionnée : $_category');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
print('Erreur: Catégorie non sélectionnée');
|
||||||
|
return 'Veuillez sélectionner une catégorie';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construction du champ de sélection d'image pour l'événement.
|
|
||||||
Widget _buildImagePicker() {
|
Widget _buildImagePicker() {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -268,7 +332,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construction du champ de saisie du lien associé à l'événement.
|
|
||||||
Widget _buildLinkField() {
|
Widget _buildLinkField() {
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -290,7 +353,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construction du bouton de soumission pour ajouter l'événement.
|
|
||||||
Widget _buildSubmitButton() {
|
Widget _buildSubmitButton() {
|
||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@@ -298,7 +360,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
_formKey.currentState!.save();
|
_formKey.currentState!.save();
|
||||||
print('Formulaire validé');
|
print('Formulaire validé');
|
||||||
|
|
||||||
// Créer l'événement en utilisant l'ID réel de l'utilisateur pour le créateur et les participants
|
|
||||||
EventModel newEvent = EventModel(
|
EventModel newEvent = EventModel(
|
||||||
id: '',
|
id: '',
|
||||||
title: _title,
|
title: _title,
|
||||||
@@ -308,7 +369,7 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
category: _category,
|
category: _category,
|
||||||
link: _link,
|
link: _link,
|
||||||
imageUrl: _imagePath ?? '',
|
imageUrl: _imagePath ?? '',
|
||||||
status: '',
|
status: 'OPEN',
|
||||||
creator: UserModel(
|
creator: UserModel(
|
||||||
userId: widget.userId,
|
userId: widget.userId,
|
||||||
nom: widget.userName,
|
nom: widget.userName,
|
||||||
@@ -327,11 +388,9 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Convertir l'événement en JSON
|
|
||||||
Map<String, dynamic> eventData = newEvent.toJson();
|
Map<String, dynamic> eventData = newEvent.toJson();
|
||||||
print('Données JSON de l\'événement: $eventData');
|
print('Données JSON de l\'événement: $eventData');
|
||||||
|
|
||||||
// Envoyer la requête POST à l'API
|
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('${Urls.baseUrl}/events'),
|
Uri.parse('${Urls.baseUrl}/events'),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
@@ -342,7 +401,6 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
print('Réponse brute: ${response.body}');
|
print('Réponse brute: ${response.body}');
|
||||||
|
|
||||||
if (response.statusCode == 201) {
|
if (response.statusCode == 201) {
|
||||||
// Création réussie
|
|
||||||
print('Événement créé avec succès');
|
print('Événement créé avec succès');
|
||||||
Fluttertoast.showToast(
|
Fluttertoast.showToast(
|
||||||
msg: "Événement créé avec succès!",
|
msg: "Événement créé avec succès!",
|
||||||
@@ -352,9 +410,8 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
fontSize: 16.0,
|
fontSize: 16.0,
|
||||||
);
|
);
|
||||||
Navigator.of(context).pop(); // Ne passez pas de valeur ici
|
Navigator.of(context).pop(); // Fermer la boîte de dialogue
|
||||||
} else {
|
} else {
|
||||||
// Gérer l'erreur
|
|
||||||
print('Erreur lors de la création de l\'événement: ${response.reasonPhrase}');
|
print('Erreur lors de la création de l\'événement: ${response.reasonPhrase}');
|
||||||
Fluttertoast.showToast(
|
Fluttertoast.showToast(
|
||||||
msg: "Erreur lors de la création de l'événement",
|
msg: "Erreur lors de la création de l'événement",
|
||||||
@@ -383,5 +440,4 @@ class _AddEventDialogState extends State<AddEventDialog> {
|
|||||||
child: const Text('Ajouter l\'événement', style: TextStyle(color: Colors.white)),
|
child: const Text('Ajouter l\'événement', style: TextStyle(color: Colors.white)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,27 +2,53 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:afterwork/data/datasources/event_remote_data_source.dart';
|
import 'package:afterwork/data/datasources/event_remote_data_source.dart';
|
||||||
|
|
||||||
/// Widget pour afficher une carte d'événement.
|
/// Widget pour afficher une carte d'événement.
|
||||||
|
/// Cette classe est utilisée pour afficher les détails d'un événement,
|
||||||
|
/// incluant son titre, sa description, son image, et des actions possibles
|
||||||
|
/// telles que réagir, commenter, partager, participer, et fermer l'événement.
|
||||||
class EventCard extends StatelessWidget {
|
class EventCard extends StatelessWidget {
|
||||||
|
// Identifiant unique de l'événement
|
||||||
final String eventId;
|
final String eventId;
|
||||||
|
// Source de données distante pour les opérations sur l'événement
|
||||||
final EventRemoteDataSource eventRemoteDataSource;
|
final EventRemoteDataSource eventRemoteDataSource;
|
||||||
|
// Identifiant de l'utilisateur
|
||||||
final String userId;
|
final String userId;
|
||||||
|
// Nom de l'utilisateur
|
||||||
final String userName;
|
final String userName;
|
||||||
|
// Prénom de l'utilisateur
|
||||||
final String userLastName;
|
final String userLastName;
|
||||||
|
// URL de l'image de profil de l'utilisateur
|
||||||
final String profileImage;
|
final String profileImage;
|
||||||
|
// Nom complet de l'utilisateur (nom + prénom)
|
||||||
final String name;
|
final String name;
|
||||||
|
// Date de publication de l'événement
|
||||||
final String datePosted;
|
final String datePosted;
|
||||||
|
// Titre de l'événement
|
||||||
final String eventTitle;
|
final String eventTitle;
|
||||||
|
// Description de l'événement
|
||||||
final String eventDescription;
|
final String eventDescription;
|
||||||
|
// URL de l'image de l'événement
|
||||||
final String eventImageUrl;
|
final String eventImageUrl;
|
||||||
final String eventStatus; // Ajout du statut de l'événement
|
// Statut de l'événement (e.g., "OPEN", "CLOSED")
|
||||||
|
final String eventStatus;
|
||||||
|
// Catégorie de l'événement
|
||||||
|
final String eventCategory;
|
||||||
|
// Nombre de réactions à l'événement
|
||||||
final int reactionsCount;
|
final int reactionsCount;
|
||||||
|
// Nombre de commentaires sur l'événement
|
||||||
final int commentsCount;
|
final int commentsCount;
|
||||||
|
// Nombre de partages de l'événement
|
||||||
final int sharesCount;
|
final int sharesCount;
|
||||||
|
// Callback pour l'action "Réagir"
|
||||||
final VoidCallback onReact;
|
final VoidCallback onReact;
|
||||||
|
// Callback pour l'action "Commenter"
|
||||||
final VoidCallback onComment;
|
final VoidCallback onComment;
|
||||||
|
// Callback pour l'action "Partager"
|
||||||
final VoidCallback onShare;
|
final VoidCallback onShare;
|
||||||
|
// Callback pour l'action "Participer"
|
||||||
final VoidCallback onParticipate;
|
final VoidCallback onParticipate;
|
||||||
|
// Callback pour afficher plus d'options
|
||||||
final VoidCallback onMoreOptions;
|
final VoidCallback onMoreOptions;
|
||||||
|
// Callback pour fermer l'événement
|
||||||
final VoidCallback onCloseEvent;
|
final VoidCallback onCloseEvent;
|
||||||
|
|
||||||
const EventCard({
|
const EventCard({
|
||||||
@@ -38,7 +64,8 @@ class EventCard extends StatelessWidget {
|
|||||||
required this.eventTitle,
|
required this.eventTitle,
|
||||||
required this.eventDescription,
|
required this.eventDescription,
|
||||||
required this.eventImageUrl,
|
required this.eventImageUrl,
|
||||||
required this.eventStatus, // Initialisation du statut de l'événement
|
required this.eventStatus,
|
||||||
|
required this.eventCategory,
|
||||||
required this.reactionsCount,
|
required this.reactionsCount,
|
||||||
required this.commentsCount,
|
required this.commentsCount,
|
||||||
required this.sharesCount,
|
required this.sharesCount,
|
||||||
@@ -52,13 +79,20 @@ class EventCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// Log du rendu de la carte d'événement
|
||||||
|
print('Rendu de l\'EventCard pour l\'événement $eventId avec statut $eventStatus');
|
||||||
|
|
||||||
return AnimatedOpacity(
|
return AnimatedOpacity(
|
||||||
opacity: 1.0,
|
opacity: 1.0,
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
child: Dismissible(
|
child: Dismissible(
|
||||||
key: ValueKey(eventId),
|
key: ValueKey(eventId),
|
||||||
direction: DismissDirection.startToEnd,
|
direction: DismissDirection.startToEnd,
|
||||||
onDismissed: (direction) => onCloseEvent(),
|
onDismissed: (direction) {
|
||||||
|
// Log du déclenchement de la fermeture de l'événement
|
||||||
|
print('Tentative de fermeture de l\'événement $eventId');
|
||||||
|
onCloseEvent();
|
||||||
|
},
|
||||||
background: Container(
|
background: Container(
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
@@ -80,13 +114,15 @@ class EventCard extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_buildHeader(context),
|
_buildHeader(context),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
_buildEventCategory(), // Affichage de la catégorie de l'événement
|
||||||
|
const SizedBox(height: 5),
|
||||||
_buildEventDetails(),
|
_buildEventDetails(),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
_buildEventImage(),
|
_buildEventImage(),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Divider(color: Colors.white.withOpacity(0.2)),
|
Divider(color: Colors.white.withOpacity(0.2)),
|
||||||
_buildInteractionRow(),
|
_buildInteractionRow(),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 5),
|
||||||
_buildParticipateButton(),
|
_buildParticipateButton(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -99,7 +135,12 @@ class EventCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construire l'en-tête de la carte avec les informations de l'utilisateur.
|
/// Construire l'en-tête de la carte avec les informations de l'utilisateur.
|
||||||
|
/// Cette méthode affiche l'image de profil, le nom de l'utilisateur, la date
|
||||||
|
/// de publication de l'événement, et le statut de l'événement.
|
||||||
Widget _buildHeader(BuildContext context) {
|
Widget _buildHeader(BuildContext context) {
|
||||||
|
// Log du rendu de l'en-tête de la carte
|
||||||
|
print('Rendu de l\'en-tête pour l\'événement $eventId');
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
@@ -134,19 +175,48 @@ class EventCard extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.more_vert, color: Colors.white),
|
icon: const Icon(Icons.more_vert, color: Colors.white),
|
||||||
onPressed: onMoreOptions,
|
onPressed: () {
|
||||||
|
// Log du déclenchement du bouton "Plus d'options"
|
||||||
|
print('Plus d\'options déclenché pour l\'événement $eventId');
|
||||||
|
onMoreOptions();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
if (eventStatus != 'CLOSED') // Masquer le bouton de fermeture si l'événement est fermé
|
if (eventStatus != 'CLOSED') // Masquer le bouton de fermeture si l'événement est fermé
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.close, color: Colors.white),
|
icon: const Icon(Icons.close, color: Colors.white),
|
||||||
onPressed: onCloseEvent,
|
onPressed: () {
|
||||||
|
// Log du déclenchement du bouton de fermeture de l'événement
|
||||||
|
print('Tentative de fermeture de l\'événement $eventId');
|
||||||
|
onCloseEvent();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Afficher la catégorie de l'événement au-dessus du titre.
|
||||||
|
/// Cette méthode affiche la catégorie en italique pour distinguer le type d'événement.
|
||||||
|
Widget _buildEventCategory() {
|
||||||
|
// Log du rendu de la catégorie de l'événement
|
||||||
|
print('Affichage de la catégorie pour l\'événement $eventId: $eventCategory');
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
eventCategory,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic, // Style en italique
|
||||||
|
fontWeight: FontWeight.w400, // Titre fin
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Afficher les détails de l'événement.
|
/// Afficher les détails de l'événement.
|
||||||
|
/// Cette méthode affiche le titre et la description de l'événement.
|
||||||
Widget _buildEventDetails() {
|
Widget _buildEventDetails() {
|
||||||
|
// Log du rendu des détails de l'événement
|
||||||
|
print('Affichage des détails pour l\'événement $eventId');
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -168,7 +238,11 @@ class EventCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Afficher l'image de l'événement.
|
/// Afficher l'image de l'événement.
|
||||||
|
/// Cette méthode affiche l'image associée à l'événement.
|
||||||
Widget _buildEventImage() {
|
Widget _buildEventImage() {
|
||||||
|
// Log du rendu de l'image de l'événement
|
||||||
|
print('Affichage de l\'image pour l\'événement $eventId');
|
||||||
|
|
||||||
return ClipRRect(
|
return ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
child: Image.network(
|
child: Image.network(
|
||||||
@@ -177,7 +251,8 @@ class EventCard extends StatelessWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
errorBuilder: (context, error, stackTrace) {
|
errorBuilder: (context, error, stackTrace) {
|
||||||
print('Erreur de chargement de l\'image: $error');
|
// Log de l'erreur lors du chargement de l'image
|
||||||
|
print('Erreur de chargement de l\'image pour l\'événement $eventId: $error');
|
||||||
return Image.asset(
|
return Image.asset(
|
||||||
'lib/assets/images/placeholder.png',
|
'lib/assets/images/placeholder.png',
|
||||||
height: 180,
|
height: 180,
|
||||||
@@ -190,29 +265,51 @@ class EventCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Afficher les icônes d'interaction (réagir, commenter, partager).
|
/// Afficher les icônes d'interaction (réagir, commenter, partager).
|
||||||
|
/// Cette méthode affiche les boutons pour réagir, commenter, et partager l'événement.
|
||||||
Widget _buildInteractionRow() {
|
Widget _buildInteractionRow() {
|
||||||
|
// Log du rendu de la ligne d'interaction de l'événement
|
||||||
|
print('Affichage des interactions pour l\'événement $eventId');
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 0.0), // Réduire le padding vertical
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceAround, // Utiliser spaceAround pour réduire l'espace
|
||||||
children: [
|
children: [
|
||||||
_buildIconButton(
|
Flexible(
|
||||||
icon: Icons.thumb_up_alt_outlined,
|
child: _buildIconButton(
|
||||||
label: 'Réagir',
|
icon: Icons.thumb_up_alt_outlined,
|
||||||
count: reactionsCount,
|
label: 'Réagir',
|
||||||
onPressed: onReact,
|
count: reactionsCount,
|
||||||
|
onPressed: () {
|
||||||
|
// Log de l'action "Réagir"
|
||||||
|
print('Réaction à l\'événement $eventId');
|
||||||
|
onReact();
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_buildIconButton(
|
Flexible(
|
||||||
icon: Icons.comment_outlined,
|
child: _buildIconButton(
|
||||||
label: 'Commenter',
|
icon: Icons.comment_outlined,
|
||||||
count: commentsCount,
|
label: 'Commenter',
|
||||||
onPressed: onComment,
|
count: commentsCount,
|
||||||
|
onPressed: () {
|
||||||
|
// Log de l'action "Commenter"
|
||||||
|
print('Commentaire sur l\'événement $eventId');
|
||||||
|
onComment();
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_buildIconButton(
|
Flexible(
|
||||||
icon: Icons.share_outlined,
|
child: _buildIconButton(
|
||||||
label: 'Partager',
|
icon: Icons.share_outlined,
|
||||||
count: sharesCount,
|
label: 'Partager',
|
||||||
onPressed: onShare,
|
count: sharesCount,
|
||||||
|
onPressed: () {
|
||||||
|
// Log de l'action "Partager"
|
||||||
|
print('Partage de l\'événement $eventId');
|
||||||
|
onShare();
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -220,12 +317,16 @@ class EventCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Bouton d'interaction personnalisé.
|
/// Bouton d'interaction personnalisé.
|
||||||
|
/// Cette méthode construit un bouton avec une icône et un label pour l'interaction.
|
||||||
Widget _buildIconButton({
|
Widget _buildIconButton({
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
required String label,
|
required String label,
|
||||||
required int count,
|
required int count,
|
||||||
required VoidCallback onPressed,
|
required VoidCallback onPressed,
|
||||||
}) {
|
}) {
|
||||||
|
// Log de la construction du bouton d'interaction
|
||||||
|
print('Construction du bouton $label pour l\'événement $eventId');
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
@@ -233,13 +334,19 @@ class EventCard extends StatelessWidget {
|
|||||||
label: Text(
|
label: Text(
|
||||||
'$label ($count)',
|
'$label ($count)',
|
||||||
style: const TextStyle(color: Colors.white70, fontSize: 12),
|
style: const TextStyle(color: Colors.white70, fontSize: 12),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bouton pour participer à l'événement.
|
/// Bouton pour participer à l'événement.
|
||||||
|
/// Cette méthode construit un bouton qui permet de participer à l'événement.
|
||||||
|
/// Si l'événement est fermé, le bouton est désactivé.
|
||||||
Widget _buildParticipateButton() {
|
Widget _buildParticipateButton() {
|
||||||
|
// Log de la construction du bouton "Participer"
|
||||||
|
print('Construction du bouton "Participer" pour l\'événement $eventId avec statut $eventStatus');
|
||||||
|
|
||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
onPressed: eventStatus == 'CLOSED' ? null : onParticipate, // Désactiver si l'événement est fermé
|
onPressed: eventStatus == 'CLOSED' ? null : onParticipate, // Désactiver si l'événement est fermé
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
@@ -258,7 +365,11 @@ class EventCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construire un badge pour afficher le statut de l'événement.
|
/// Construire un badge pour afficher le statut de l'événement.
|
||||||
|
/// Cette méthode affiche un badge avec le statut de l'événement ("OPEN" ou "CLOSED").
|
||||||
Widget _buildStatusBadge() {
|
Widget _buildStatusBadge() {
|
||||||
|
// Log de la construction du badge de statut
|
||||||
|
print('Construction du badge de statut pour l\'événement $eventId: $eventStatus');
|
||||||
|
|
||||||
Color badgeColor;
|
Color badgeColor;
|
||||||
switch (eventStatus) {
|
switch (eventStatus) {
|
||||||
case 'CLOSED':
|
case 'CLOSED':
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ class _EventScreenState extends State<EventScreen> {
|
|||||||
userLastName: widget.userLastName,
|
userLastName: widget.userLastName,
|
||||||
profileImage: 'lib/assets/images/profile_picture.png',
|
profileImage: 'lib/assets/images/profile_picture.png',
|
||||||
name: '${widget.userName} ${widget.userLastName}',
|
name: '${widget.userName} ${widget.userLastName}',
|
||||||
datePosted: 'Posté le 24/08/2024',
|
eventCategory: event.category,
|
||||||
|
datePosted: event.date,
|
||||||
eventTitle: event.title,
|
eventTitle: event.title,
|
||||||
eventDescription: event.description,
|
eventDescription: event.description,
|
||||||
eventImageUrl: event.imageUrl ?? 'lib/assets/images/placeholder.png',
|
eventImageUrl: event.imageUrl ?? 'lib/assets/images/placeholder.png',
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ flutter:
|
|||||||
- lib/assets/images/background.webp
|
- lib/assets/images/background.webp
|
||||||
- lib/assets/images/profile_picture.png
|
- lib/assets/images/profile_picture.png
|
||||||
- lib/assets/images/placeholder.png
|
- lib/assets/images/placeholder.png
|
||||||
|
- lib/assets/json/event_categories.json
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
# assets:
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
|
|||||||
Reference in New Issue
Block a user