import 'package:flutter/material.dart'; import '../../../core/constants/design_system.dart'; import '../../../core/constants/env_config.dart'; import '../../../core/utils/date_formatter.dart'; import '../../../data/models/event_model.dart'; import '../../widgets/animated_widgets.dart'; import '../../widgets/event_header.dart'; import '../../widgets/event_image.dart'; import '../../widgets/event_interaction_row.dart'; import '../../widgets/event_status_badge.dart'; import '../../widgets/swipe_background.dart'; /// Widget représentant une carte d'événement avec design moderne et compact. /// /// Cette carte affiche les informations principales de l'événement avec /// diverses options d'interaction et un design optimisé. /// /// **Fonctionnalités:** /// - Affichage des informations de l'événement /// - Interactions (réagir, commenter, partager, participer) /// - Actions de fermeture/réouverture /// - Swipe pour actions rapides /// - Description expandable class EventCard extends StatefulWidget { const EventCard({ required this.event, required this.userId, required this.userFirstName, required this.userLastName, required this.profileImageUrl, required this.status, required this.onReact, required this.onComment, required this.onShare, required this.onParticipate, required this.onCloseEvent, required this.onReopenEvent, required this.onRemoveEvent, super.key, }); final EventModel event; final String userId; final String userFirstName; final String userLastName; final String profileImageUrl; final String status; final VoidCallback onReact; final VoidCallback onComment; final VoidCallback onShare; final VoidCallback onParticipate; final VoidCallback onCloseEvent; final VoidCallback onReopenEvent; final Function(String) onRemoveEvent; @override State createState() => _EventCardState(); } class _EventCardState extends State { // ============================================================================ // ÉTATS // ============================================================================ bool _isDescriptionExpanded = false; static const int _descriptionThreshold = 100; bool get _isClosed => widget.event.status.toLowerCase() == 'fermé'; bool get _shouldTruncateDescription => widget.event.description.length > _descriptionThreshold; // ============================================================================ // BUILD // ============================================================================ @override Widget build(BuildContext context) { final theme = Theme.of(context); final menuKey = GlobalKey(); return Dismissible( key: ValueKey(widget.event.id), direction: _isClosed ? DismissDirection.startToEnd : DismissDirection.endToStart, onDismissed: _handleDismiss, background: _buildSwipeBackground(), child: AnimatedCard( margin: const EdgeInsets.only(bottom: DesignSystem.spacingMd), borderRadius: DesignSystem.borderRadiusMd, elevation: 1, hoverElevation: 3, padding: EdgeInsets.zero, child: Padding( padding: const EdgeInsets.all(DesignSystem.spacingLg), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(menuKey), const SizedBox(height: DesignSystem.spacingMd), Row( children: [ Expanded(child: _buildTitle(theme)), const SizedBox(width: DesignSystem.spacingSm), _buildStatusBadge(theme), ], ), const SizedBox(height: DesignSystem.spacingSm), _buildDescription(theme), if (widget.event.imageUrl != null) ...[ const SizedBox(height: DesignSystem.spacingMd), _buildImage(theme), ], const SizedBox(height: DesignSystem.spacingMd), Divider(height: 1, color: theme.dividerColor.withOpacity(0.5)), const SizedBox(height: DesignSystem.spacingSm), _buildInteractions(theme), ], ), ), ), ); } // ============================================================================ // WIDGETS // ============================================================================ /// Construit l'en-tête de l'événement. Widget _buildHeader(GlobalKey menuKey) { return EventHeader( creatorFirstName: widget.event.creatorFirstName, creatorLastName: widget.event.creatorLastName, profileImageUrl: widget.event.profileImageUrl, eventDate: widget.event.startDate, imageUrl: widget.event.imageUrl, menuKey: menuKey, menuContext: context, location: widget.event.location, onClose: () { if (EnvConfig.enableDetailedLogs) { debugPrint('[EventCard] Menu fermé pour ${widget.event.id}'); } }, ); } /// Construit le badge de statut. Widget _buildStatusBadge(ThemeData theme) { return EventStatusBadge(status: widget.status); } /// Construit le titre. Widget _buildTitle(ThemeData theme) { return Text( widget.event.title, style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, fontSize: 17, height: 1.3, ), maxLines: 2, overflow: TextOverflow.ellipsis, ); } /// Construit la description avec expansion. Widget _buildDescription(ThemeData theme) { final description = widget.event.description; final displayText = _isDescriptionExpanded || !_shouldTruncateDescription ? description : '${description.substring(0, _descriptionThreshold)}...'; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( displayText, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurface.withOpacity(0.65), fontSize: 13, height: 1.4, ), maxLines: _isDescriptionExpanded ? null : 2, overflow: _isDescriptionExpanded ? TextOverflow.visible : TextOverflow.ellipsis, ), if (_shouldTruncateDescription) ...[ const SizedBox(height: 2), GestureDetector( onTap: _toggleDescription, child: Text( _isDescriptionExpanded ? 'Voir moins' : 'Voir plus', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.primary, fontWeight: FontWeight.w500, fontSize: 12, ), ), ), ], ], ); } /// Construit l'image de l'événement. Widget _buildImage(ThemeData theme) { return EventImage( imageUrl: widget.event.imageUrl, heroTag: 'event_image_${widget.event.id}', eventTitle: widget.event.title, ); } /// Construit les interactions. Widget _buildInteractions(ThemeData theme) { return EventInteractionRow( onReact: widget.onReact, onComment: widget.onComment, onShare: widget.onShare, reactionsCount: widget.event.reactionsCount, commentsCount: widget.event.commentsCount, sharesCount: widget.event.sharesCount, ); } /// Construit l'arrière-plan du swipe. Widget _buildSwipeBackground() { return SwipeBackground( color: _isClosed ? Colors.green : Colors.red, icon: _isClosed ? Icons.lock_open : Icons.lock, label: _isClosed ? 'Rouvrir' : 'Fermer', ); } // ============================================================================ // ACTIONS // ============================================================================ /// Bascule l'expansion de la description. void _toggleDescription() { setState(() { _isDescriptionExpanded = !_isDescriptionExpanded; }); } /// Gère le swipe pour fermer/rouvrir. void _handleDismiss(DismissDirection direction) { if (_isClosed) { widget.onReopenEvent(); } else { widget.onCloseEvent(); widget.onRemoveEvent(widget.event.id); } } }