Clean project: remove test files, debug logs, and add documentation
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
/// Page de détails d'un événement
|
||||
library event_detail_page;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../bloc/evenements_bloc.dart';
|
||||
import '../../bloc/evenements_state.dart';
|
||||
import '../../data/models/evenement_model.dart';
|
||||
import '../widgets/inscription_event_dialog.dart';
|
||||
import '../widgets/edit_event_dialog.dart';
|
||||
|
||||
class EventDetailPage extends StatelessWidget {
|
||||
final EvenementModel evenement;
|
||||
|
||||
const EventDetailPage({
|
||||
super.key,
|
||||
required this.evenement,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Détails de l\'événement'),
|
||||
backgroundColor: const Color(0xFF3B82F6),
|
||||
foregroundColor: Colors.white,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () => _showEditDialog(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: BlocBuilder<EvenementsBloc, EvenementsState>(
|
||||
builder: (context, state) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(),
|
||||
_buildInfoSection(),
|
||||
_buildDescriptionSection(),
|
||||
if (evenement.lieu != null) _buildLocationSection(),
|
||||
_buildParticipantsSection(),
|
||||
const SizedBox(height: 80), // Espace pour le bouton flottant
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
floatingActionButton: _buildInscriptionButton(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
const Color(0xFF3B82F6),
|
||||
const Color(0xFF3B82F6).withOpacity(0.8),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
_getTypeLabel(evenement.type),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
evenement.titre,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatutColor(evenement.statut),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text(
|
||||
_getStatutLabel(evenement.statut),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoSection() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildInfoRow(
|
||||
Icons.calendar_today,
|
||||
'Date de début',
|
||||
_formatDate(evenement.dateDebut),
|
||||
),
|
||||
const Divider(),
|
||||
_buildInfoRow(
|
||||
Icons.event,
|
||||
'Date de fin',
|
||||
_formatDate(evenement.dateFin),
|
||||
),
|
||||
if (evenement.maxParticipants != null) ...[
|
||||
const Divider(),
|
||||
_buildInfoRow(
|
||||
Icons.people,
|
||||
'Places',
|
||||
'${evenement.participantsActuels} / ${evenement.maxParticipants}',
|
||||
),
|
||||
],
|
||||
if (evenement.organisateurNom != null) ...[
|
||||
const Divider(),
|
||||
_buildInfoRow(
|
||||
Icons.person,
|
||||
'Organisateur',
|
||||
evenement.organisateurNom!,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoRow(IconData icon, String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, color: const Color(0xFF3B82F6), size: 20),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDescriptionSection() {
|
||||
if (evenement.description == null) return const SizedBox.shrink();
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Description',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
evenement.description!,
|
||||
style: const TextStyle(fontSize: 14, height: 1.5),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLocationSection() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Lieu',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.location_on, color: Color(0xFF3B82F6)),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
evenement.lieu!,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildParticipantsSection() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Participants',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${evenement.participantsActuels} inscrits',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[100],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.info_outline, size: 20),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'La liste des participants est visible uniquement pour les organisateurs',
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInscriptionButton(BuildContext context) {
|
||||
const isInscrit = false; // TODO: Vérifier si l'utilisateur est inscrit
|
||||
final placesRestantes = (evenement.maxParticipants ?? 0) -
|
||||
evenement.participantsActuels;
|
||||
final isComplet = placesRestantes <= 0 && evenement.maxParticipants != null;
|
||||
|
||||
return FloatingActionButton.extended(
|
||||
onPressed: (isInscrit || !isComplet)
|
||||
? () => _showInscriptionDialog(context, isInscrit)
|
||||
: null,
|
||||
backgroundColor: isInscrit ? Colors.red : const Color(0xFF3B82F6),
|
||||
icon: Icon(isInscrit ? Icons.cancel : Icons.check),
|
||||
label: Text(
|
||||
isInscrit ? 'Se désinscrire' : (isComplet ? 'Complet' : 'S\'inscrire'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showInscriptionDialog(BuildContext context, bool isInscrit) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: context.read<EvenementsBloc>(),
|
||||
child: InscriptionEventDialog(
|
||||
evenement: evenement,
|
||||
isInscrit: isInscrit,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showEditDialog(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: context.read<EvenementsBloc>(),
|
||||
child: EditEventDialog(evenement: evenement),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _formatDate(DateTime date) {
|
||||
final months = [
|
||||
'janvier', 'février', 'mars', 'avril', 'mai', 'juin',
|
||||
'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'
|
||||
];
|
||||
return '${date.day} ${months[date.month - 1]} ${date.year} à ${date.hour}:${date.minute.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
String _getTypeLabel(TypeEvenement type) {
|
||||
switch (type) {
|
||||
case TypeEvenement.assembleeGenerale:
|
||||
return 'Assemblée Générale';
|
||||
case TypeEvenement.reunion:
|
||||
return 'Réunion';
|
||||
case TypeEvenement.formation:
|
||||
return 'Formation';
|
||||
case TypeEvenement.conference:
|
||||
return 'Conférence';
|
||||
case TypeEvenement.atelier:
|
||||
return 'Atelier';
|
||||
case TypeEvenement.seminaire:
|
||||
return 'Séminaire';
|
||||
case TypeEvenement.evenementSocial:
|
||||
return 'Événement Social';
|
||||
case TypeEvenement.manifestation:
|
||||
return 'Manifestation';
|
||||
case TypeEvenement.celebration:
|
||||
return 'Célébration';
|
||||
case TypeEvenement.autre:
|
||||
return 'Autre';
|
||||
}
|
||||
}
|
||||
|
||||
String _getStatutLabel(StatutEvenement statut) {
|
||||
switch (statut) {
|
||||
case StatutEvenement.planifie:
|
||||
return 'Planifié';
|
||||
case StatutEvenement.confirme:
|
||||
return 'Confirmé';
|
||||
case StatutEvenement.enCours:
|
||||
return 'En cours';
|
||||
case StatutEvenement.termine:
|
||||
return 'Terminé';
|
||||
case StatutEvenement.annule:
|
||||
return 'Annulé';
|
||||
case StatutEvenement.reporte:
|
||||
return 'Reporté';
|
||||
}
|
||||
}
|
||||
|
||||
Color _getStatutColor(StatutEvenement statut) {
|
||||
switch (statut) {
|
||||
case StatutEvenement.planifie:
|
||||
return Colors.blue;
|
||||
case StatutEvenement.confirme:
|
||||
return Colors.green;
|
||||
case StatutEvenement.enCours:
|
||||
return Colors.orange;
|
||||
case StatutEvenement.termine:
|
||||
return Colors.grey;
|
||||
case StatutEvenement.annule:
|
||||
return Colors.red;
|
||||
case StatutEvenement.reporte:
|
||||
return Colors.purple;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user