import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '../../../core/constants/design_system.dart'; import '../../../domain/entities/social_post.dart'; import 'media_picker.dart'; /// Dialogue d'édition de post existant avec support d'images et vidéos. class EditPostDialog extends StatefulWidget { const EditPostDialog({ required this.post, required this.onPostUpdated, super.key, }); final SocialPost post; final Future Function(String content, List medias) onPostUpdated; @override State createState() => _EditPostDialogState(); /// Affiche le dialogue d'édition de post static Future show({ required BuildContext context, required SocialPost post, required Future Function(String content, List medias) onPostUpdated, }) { return showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => EditPostDialog( post: post, onPostUpdated: onPostUpdated, ), ); } } class _EditPostDialogState extends State { late final TextEditingController _contentController; final FocusNode _contentFocusNode = FocusNode(); final GlobalKey _formKey = GlobalKey(); List _selectedMedias = []; bool _isUpdating = false; @override void initState() { super.initState(); _contentController = TextEditingController(text: widget.post.content); // Note: Les médias existants du post sont déjà stockés sous forme d'URLs // dans widget.post.mediaUrls. Ils seront affichés via ces URLs. // _selectedMedias permet d'ajouter de NOUVEAUX médias locaux. // Lors de la sauvegarde, il faut combiner: // - Les URLs existantes (widget.post.mediaUrls) // - Les nouveaux médias uploadés (URLs générées depuis _selectedMedias) _selectedMedias = []; // Auto-focus sur le champ de texte Future.delayed(const Duration(milliseconds: 300), () { if (mounted) { _contentFocusNode.requestFocus(); } }); } @override void dispose() { _contentController.dispose(); _contentFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final mediaQuery = MediaQuery.of(context); return Container( decoration: BoxDecoration( color: theme.scaffoldBackgroundColor, borderRadius: const BorderRadius.vertical( top: Radius.circular(DesignSystem.radiusLg), ), ), padding: EdgeInsets.only( bottom: mediaQuery.viewInsets.bottom, ), child: SafeArea( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(DesignSystem.spacingLg), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildHeader(theme), const SizedBox(height: DesignSystem.spacingLg), _buildUserInfo(theme), const SizedBox(height: DesignSystem.spacingMd), _buildContentField(theme), const SizedBox(height: DesignSystem.spacingLg), MediaPicker( onMediasChanged: (medias) { setState(() { _selectedMedias = medias; }); }, initialMedias: _selectedMedias, ), const SizedBox(height: DesignSystem.spacingLg), _buildActions(theme), ], ), ), ), ), ); } Widget _buildHeader(ThemeData theme) { return Row( children: [ // Handle Container( width: 40, height: 4, decoration: BoxDecoration( color: theme.colorScheme.onSurface.withOpacity(0.2), borderRadius: BorderRadius.circular(2), ), ), const Spacer(), // Titre Text( 'Modifier le post', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, fontSize: 17, ), ), const Spacer(), // Bouton fermer IconButton( icon: const Icon(Icons.close_rounded, size: 22), onPressed: () => Navigator.of(context).pop(), padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 40, minHeight: 40), ), ], ); } Widget _buildUserInfo(ThemeData theme) { return Row( children: [ // Avatar CircleAvatar( radius: 20, backgroundColor: theme.colorScheme.primaryContainer, backgroundImage: widget.post.userProfileImageUrl.isNotEmpty ? NetworkImage(widget.post.userProfileImageUrl) : null, child: widget.post.userProfileImageUrl.isEmpty ? Icon( Icons.person_rounded, size: 24, color: theme.colorScheme.onPrimaryContainer, ) : null, ), const SizedBox(width: DesignSystem.spacingMd), // Nom Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.post.authorFullName, style: theme.textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w600, fontSize: 14, ), ), const SizedBox(height: 2), Row( children: [ Icon( Icons.edit_rounded, size: 14, color: theme.colorScheme.onSurface.withOpacity(0.6), ), const SizedBox(width: 4), Text( 'Édition', style: theme.textTheme.bodySmall?.copyWith( fontSize: 12, color: theme.colorScheme.onSurface.withOpacity(0.6), ), ), ], ), ], ), ), ], ); } Widget _buildContentField(ThemeData theme) { return Form( key: _formKey, child: TextFormField( controller: _contentController, focusNode: _contentFocusNode, decoration: InputDecoration( hintText: 'Modifiez votre post...', hintStyle: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onSurface.withOpacity(0.4), fontSize: 16, ), border: InputBorder.none, contentPadding: EdgeInsets.zero, ), style: theme.textTheme.bodyMedium?.copyWith( fontSize: 16, height: 1.5, ), maxLines: 8, minLines: 3, maxLength: 500, validator: (value) { if ((value == null || value.trim().isEmpty) && _selectedMedias.isEmpty) { return 'Ajoutez du texte ou des médias'; } return null; }, ), ); } Widget _buildActions(ThemeData theme) { final hasChanges = _contentController.text != widget.post.content || _selectedMedias.isNotEmpty; return Row( children: [ // Indicateur de caractères Expanded( child: Text( '${_contentController.text.length}/500', style: theme.textTheme.bodySmall?.copyWith( fontSize: 12, color: theme.colorScheme.onSurface.withOpacity(0.5), ), ), ), const SizedBox(width: DesignSystem.spacingMd), // Bouton Annuler TextButton( onPressed: _isUpdating ? null : () => Navigator.of(context).pop(), child: const Text('Annuler'), ), const SizedBox(width: DesignSystem.spacingSm), // Bouton Enregistrer FilledButton( onPressed: (_isUpdating || !hasChanges) ? null : _handleUpdate, child: _isUpdating ? const SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : const Text('Enregistrer'), ), ], ); } Future _handleUpdate() async { if (!_formKey.currentState!.validate()) { return; } setState(() { _isUpdating = true; }); try { await widget.onPostUpdated( _contentController.text.trim(), _selectedMedias, ); if (mounted) { Navigator.of(context).pop(); } } catch (e) { if (mounted) { final theme = Theme.of(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Erreur lors de la mise à jour: ${e.toString()}'), backgroundColor: theme.colorScheme.error, ), ); } } finally { if (mounted) { setState(() { _isUpdating = false; }); } } } }