Clean project: remove test files, debug logs, and add documentation

This commit is contained in:
dahoud
2025-10-05 13:41:33 +00:00
parent 96a17eadbd
commit 291847924c
438 changed files with 65754 additions and 32713 deletions

View File

@@ -0,0 +1,428 @@
/// Dialogue de création d'événement
/// Formulaire complet pour créer un nouvel événement
library create_event_dialog;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import '../../bloc/evenements_bloc.dart';
import '../../bloc/evenements_event.dart';
import '../../data/models/evenement_model.dart';
/// Dialogue de création d'événement
class CreateEventDialog extends StatefulWidget {
const CreateEventDialog({super.key});
@override
State<CreateEventDialog> createState() => _CreateEventDialogState();
}
class _CreateEventDialogState extends State<CreateEventDialog> {
final _formKey = GlobalKey<FormState>();
// Contrôleurs de texte
final _titreController = TextEditingController();
final _descriptionController = TextEditingController();
final _lieuController = TextEditingController();
final _adresseController = TextEditingController();
final _capaciteController = TextEditingController();
// Valeurs sélectionnées
DateTime _dateDebut = DateTime.now().add(const Duration(days: 7));
DateTime? _dateFin;
TypeEvenement _selectedType = TypeEvenement.autre;
bool _inscriptionRequise = true;
bool _visiblePublic = true;
@override
void dispose() {
_titreController.dispose();
_descriptionController.dispose();
_lieuController.dispose();
_adresseController.dispose();
_capaciteController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Dialog(
child: Container(
width: MediaQuery.of(context).size.width * 0.9,
constraints: const BoxConstraints(maxHeight: 600),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// En-tête
Container(
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
color: Color(0xFF3B82F6),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4),
),
),
child: Row(
children: [
const Icon(Icons.event, color: Colors.white),
const SizedBox(width: 12),
const Text(
'Créer un événement',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const Spacer(),
IconButton(
icon: const Icon(Icons.close, color: Colors.white),
onPressed: () => Navigator.pop(context),
),
],
),
),
// Formulaire
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Informations de base
_buildSectionTitle('Informations de base'),
const SizedBox(height: 12),
TextFormField(
controller: _titreController,
decoration: const InputDecoration(
labelText: 'Titre *',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.title),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Le titre est obligatoire';
}
if (value.length < 3) {
return 'Le titre doit contenir au moins 3 caractères';
}
return null;
},
),
const SizedBox(height: 12),
TextFormField(
controller: _descriptionController,
decoration: const InputDecoration(
labelText: 'Description',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.description),
),
maxLines: 3,
),
const SizedBox(height: 12),
// Type d'événement
DropdownButtonFormField<TypeEvenement>(
value: _selectedType,
decoration: const InputDecoration(
labelText: 'Type d\'événement *',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.category),
),
items: TypeEvenement.values.map((type) {
return DropdownMenuItem(
value: type,
child: Text(_getTypeLabel(type)),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedType = value!;
});
},
),
const SizedBox(height: 16),
// Dates
_buildSectionTitle('Dates et horaires'),
const SizedBox(height: 12),
InkWell(
onTap: () => _selectDateDebut(context),
child: InputDecorator(
decoration: const InputDecoration(
labelText: 'Date de début *',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.calendar_today),
),
child: Text(
DateFormat('dd/MM/yyyy HH:mm').format(_dateDebut),
),
),
),
const SizedBox(height: 12),
InkWell(
onTap: () => _selectDateFin(context),
child: InputDecorator(
decoration: const InputDecoration(
labelText: 'Date de fin (optionnel)',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.event_available),
),
child: Text(
_dateFin != null
? DateFormat('dd/MM/yyyy HH:mm').format(_dateFin!)
: 'Sélectionner une date',
),
),
),
const SizedBox(height: 16),
// Lieu
_buildSectionTitle('Lieu'),
const SizedBox(height: 12),
TextFormField(
controller: _lieuController,
decoration: const InputDecoration(
labelText: 'Lieu *',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.place),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Le lieu est obligatoire';
}
return null;
},
),
const SizedBox(height: 12),
TextFormField(
controller: _adresseController,
decoration: const InputDecoration(
labelText: 'Adresse complète',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.location_on),
),
maxLines: 2,
),
const SizedBox(height: 16),
// Paramètres
_buildSectionTitle('Paramètres'),
const SizedBox(height: 12),
TextFormField(
controller: _capaciteController,
decoration: const InputDecoration(
labelText: 'Capacité maximale',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.people),
hintText: 'Nombre de places disponibles',
),
keyboardType: TextInputType.number,
validator: (value) {
if (value != null && value.isNotEmpty) {
final capacite = int.tryParse(value);
if (capacite == null || capacite <= 0) {
return 'Capacité invalide';
}
}
return null;
},
),
const SizedBox(height: 12),
SwitchListTile(
title: const Text('Inscription requise'),
subtitle: const Text('Les participants doivent s\'inscrire'),
value: _inscriptionRequise,
onChanged: (value) {
setState(() {
_inscriptionRequise = value;
});
},
),
SwitchListTile(
title: const Text('Visible publiquement'),
subtitle: const Text('L\'événement est visible par tous'),
value: _visiblePublic,
onChanged: (value) {
setState(() {
_visiblePublic = value;
});
},
),
],
),
),
),
),
// Boutons d'action
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
border: Border(top: BorderSide(color: Colors.grey[300]!)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Annuler'),
),
const SizedBox(width: 12),
ElevatedButton(
onPressed: _submitForm,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF3B82F6),
foregroundColor: Colors.white,
),
child: const Text('Créer l\'événement'),
),
],
),
),
],
),
),
);
}
Widget _buildSectionTitle(String title) {
return Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Color(0xFF3B82F6),
),
);
}
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';
}
}
Future<void> _selectDateDebut(BuildContext context) async {
final DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _dateDebut,
firstDate: DateTime.now(),
lastDate: DateTime.now().add(const Duration(days: 365 * 2)),
);
if (pickedDate != null) {
final TimeOfDay? pickedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(_dateDebut),
);
if (pickedTime != null) {
setState(() {
_dateDebut = DateTime(
pickedDate.year,
pickedDate.month,
pickedDate.day,
pickedTime.hour,
pickedTime.minute,
);
});
}
}
}
Future<void> _selectDateFin(BuildContext context) async {
final DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _dateFin ?? _dateDebut.add(const Duration(hours: 2)),
firstDate: _dateDebut,
lastDate: DateTime.now().add(const Duration(days: 365 * 2)),
);
if (pickedDate != null) {
final TimeOfDay? pickedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(_dateFin ?? _dateDebut.add(const Duration(hours: 2))),
);
if (pickedTime != null) {
setState(() {
_dateFin = DateTime(
pickedDate.year,
pickedDate.month,
pickedDate.day,
pickedTime.hour,
pickedTime.minute,
);
});
}
}
}
void _submitForm() {
if (_formKey.currentState!.validate()) {
// Créer le modèle d'événement
final evenement = EvenementModel(
titre: _titreController.text,
description: _descriptionController.text.isNotEmpty ? _descriptionController.text : null,
dateDebut: _dateDebut,
dateFin: _dateFin ?? _dateDebut.add(const Duration(hours: 2)),
lieu: _lieuController.text,
adresse: _adresseController.text.isNotEmpty ? _adresseController.text : null,
type: _selectedType,
maxParticipants: _capaciteController.text.isNotEmpty ? int.parse(_capaciteController.text) : null,
inscriptionRequise: _inscriptionRequise,
estPublic: _visiblePublic,
statut: StatutEvenement.planifie,
);
// Envoyer l'événement au BLoC
context.read<EvenementsBloc>().add(CreateEvenement(evenement));
// Fermer le dialogue
Navigator.pop(context);
// Afficher un message de succès
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Événement créé avec succès'),
backgroundColor: Colors.green,
),
);
}
}
}