fix(chat): Correction race condition + Implémentation TODOs

## Corrections Critiques

### Race Condition - Statuts de Messages
- Fix : Les icônes de statut (✓, ✓✓, ✓✓ bleu) ne s'affichaient pas
- Cause : WebSocket delivery confirmations arrivaient avant messages locaux
- Solution : Pattern Optimistic UI dans chat_bloc.dart
  - Création message temporaire immédiate
  - Ajout à la liste AVANT requête HTTP
  - Remplacement par message serveur à la réponse
- Fichier : lib/presentation/state_management/chat_bloc.dart

## Implémentation TODOs (13/21)

### Social (social_header_widget.dart)
-  Copier lien du post dans presse-papiers
-  Partage natif via Share.share()
-  Dialogue de signalement avec 5 raisons

### Partage (share_post_dialog.dart)
-  Interface sélection d'amis avec checkboxes
-  Partage externe via Share API

### Média (media_upload_service.dart)
-  Parsing JSON réponse backend
-  Méthode deleteMedia() pour suppression
-  Génération miniature vidéo

### Posts (create_post_dialog.dart, edit_post_dialog.dart)
-  Extraction URL depuis uploads
-  Documentation chargement médias

### Chat (conversations_screen.dart)
-  Navigation vers notifications
-  ConversationSearchDelegate pour recherche

## Nouveaux Fichiers

### Configuration
- build-prod.ps1 : Script build production avec dart-define
- lib/core/constants/env_config.dart : Gestion environnements

### Documentation
- TODOS_IMPLEMENTED.md : Documentation complète TODOs

## Améliorations

### Architecture
- Refactoring injection de dépendances
- Amélioration routing et navigation
- Optimisation providers (UserProvider, FriendsProvider)

### UI/UX
- Amélioration thème et couleurs
- Optimisation animations
- Meilleure gestion erreurs

### Services
- Configuration API avec env_config
- Amélioration datasources (events, users)
- Optimisation modèles de données
This commit is contained in:
dahoud
2026-01-10 10:43:17 +00:00
parent 06031b01f2
commit 92612abbd7
321 changed files with 43137 additions and 4285 deletions

View File

@@ -1,39 +1,39 @@
import 'dart:io'; // Pour l'usage des fichiers (image)
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'dart:io'; // Pour l'usage des fichiers (image)
import '../../widgets/fields/category_field.dart'; // Importation des widgets personnalisés
import '../../../core/utils/app_logger.dart';
import '../../widgets/date_picker.dart';
import '../../widgets/fields/accessibility_field.dart';
import '../../widgets/fields/accommodation_info_field.dart';
import '../../widgets/fields/attendees_field.dart';
import '../../widgets/fields/category_field.dart'; // Importation des widgets personnalisés
import '../../widgets/fields/description_field.dart';
import '../../widgets/fields/link_field.dart';
import '../../widgets/fields/location_field.dart';
import '../../widgets/submit_button.dart';
import '../../widgets/fields/title_field.dart';
import '../../widgets/image_preview_picker.dart';
import '../../widgets/fields/tags_field.dart';
import '../../widgets/fields/attendees_field.dart';
import '../../widgets/fields/organizer_field.dart';
import '../../widgets/fields/transport_info_field.dart';
import '../../widgets/fields/accommodation_info_field.dart';
import '../../widgets/fields/parking_field.dart';
import '../../widgets/fields/participation_fee_field.dart';
import '../../widgets/fields/privacy_rules_field.dart';
import '../../widgets/fields/security_protocol_field.dart';
import '../../widgets/fields/parking_field.dart';
import '../../widgets/fields/accessibility_field.dart';
import '../../widgets/fields/participation_fee_field.dart';
import '../../widgets/fields/tags_field.dart';
import '../../widgets/fields/title_field.dart';
import '../../widgets/fields/transport_info_field.dart';
import '../../widgets/image_preview_picker.dart';
import '../../widgets/submit_button.dart';
/// Page pour ajouter un événement
/// Permet à l'utilisateur de remplir un formulaire avec des détails sur l'événement
class AddEventPage extends StatefulWidget {
const AddEventPage({
required this.userId, required this.userFirstName, required this.userLastName, super.key,
});
final String userId;
final String userFirstName;
final String userLastName;
const AddEventPage({
super.key,
required this.userId,
required this.userFirstName,
required this.userLastName,
});
@override
_AddEventPageState createState() => _AddEventPageState();
}
@@ -52,16 +52,16 @@ class _AddEventPageState extends State<AddEventPage> {
String _organizer = '';
List<String> _tags = [];
int _maxParticipants = 0;
LatLng? _selectedLatLng = const LatLng(5.348722, -3.985038); // Coordonnées par défaut
final LatLng _selectedLatLng = const LatLng(5.348722, -3.985038); // Coordonnées par défaut
File? _selectedImageFile; // Image sélectionnée
String _status = 'Actif';
String _organizerEmail = '';
String _organizerPhone = '';
final String _status = 'Actif';
final String _organizerEmail = '';
final String _organizerPhone = '';
int _participationFee = 0;
String _privacyRules = '';
String _transportInfo = '';
String _accommodationInfo = '';
bool _isAccessible = false;
final bool _isAccessible = false;
bool _hasParking = false;
String _securityProtocol = '';
@@ -83,7 +83,7 @@ class _AddEventPageState extends State<AddEventPage> {
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
@@ -173,27 +173,18 @@ class _AddEventPageState extends State<AddEventPage> {
),
const SizedBox(height: 12),
SubmitButton(
text: 'Créer l\'événement',
onPressed: () {
if (_formKey.currentState?.validate() ?? false) {
// Log des données de l'événement avant l'envoi
print('Titre de l\'événement : $_title');
print('Description de l\'événement : $_description');
print('Date de début : $_selectedDate');
print('Date de fin : $_endDate');
print('Lieu : $_location');
print('Catégorie : $_category');
print('Lien de l\'événement : $_link');
print('Organisateur : $_organizer');
print('Tags : $_tags');
print('Maximum de participants : $_maxParticipants');
print('Image sélectionnée : $_selectedImageFile');
print('Transport : $_transportInfo');
print('Hébergement : $_accommodationInfo');
print('Règles de confidentialité : $_privacyRules');
print('Protocole de sécurité : $_securityProtocol');
print('Parking disponible : $_hasParking');
print('Accessibilité : $_isAccessible');
print('Frais de participation : $_participationFee');
AppLogger.i(
'Création d\'événement: titre=$_title, lieu=$_location, catégorie=$_category, participants=$_maxParticipants',
tag: 'AddEventDialog',
);
AppLogger.d(
'Détails: description=${_description.length} chars, dates=$_selectedDate -> $_endDate, tags=${_tags.length}, image=${_selectedImageFile != null}',
tag: 'AddEventDialog',
);
// Logique d'envoi des données vers le backend...
ScaffoldMessenger.of(context).showSnackBar(
@@ -219,7 +210,7 @@ class _AddEventPageState extends State<AddEventPage> {
// En-tête de section pour mieux organiser les champs
Widget _buildSectionHeader(String title) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
padding: const EdgeInsets.symmetric(vertical: 8),
child: Text(
title,
style: const TextStyle(