From 0b0d9a81e2e85b65e29d25d5287c26bd679aeac5 Mon Sep 17 00:00:00 2001 From: Abraham Date: Thu, 15 Jan 2026 21:34:40 -0800 Subject: [PATCH] thumbails fix --- lib/pages/videos/gestor_videos_page.dart | 16 +------- .../edit_video_dialog.dart | 41 +++++++++++++++++++ .../videos/widgets/premium_upload_dialog.dart | 38 +++++++++++++++++ 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/lib/pages/videos/gestor_videos_page.dart b/lib/pages/videos/gestor_videos_page.dart index 739e085..4520adc 100644 --- a/lib/pages/videos/gestor_videos_page.dart +++ b/lib/pages/videos/gestor_videos_page.dart @@ -386,7 +386,7 @@ class _GestorVideosPageState extends State { fit: BoxFit.cover, ) : _buildThumbnailPlaceholder(), - // Overlay con icono de play + // Overlay con gradiente Positioned.fill( child: Container( decoration: BoxDecoration( @@ -399,20 +399,6 @@ class _GestorVideosPageState extends State { ], ), ), - child: Center( - child: Container( - padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.9), - shape: BoxShape.circle, - ), - child: Icon( - Icons.play_arrow_rounded, - size: 16, - color: AppTheme.of(context).primaryColor, - ), - ), - ), ), ), ], diff --git a/lib/pages/videos/widgets/gestor_videos_widgets/edit_video_dialog.dart b/lib/pages/videos/widgets/gestor_videos_widgets/edit_video_dialog.dart index 06c4612..3e223a4 100644 --- a/lib/pages/videos/widgets/gestor_videos_widgets/edit_video_dialog.dart +++ b/lib/pages/videos/widgets/gestor_videos_widgets/edit_video_dialog.dart @@ -3,6 +3,8 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:chewie/chewie.dart'; import 'package:video_player/video_player.dart'; +import 'package:get_thumbnail_video/index.dart'; +import 'package:get_thumbnail_video/video_thumbnail.dart'; import 'package:gap/gap.dart'; import 'package:energy_media/theme/theme.dart'; import 'package:energy_media/models/media/media_models.dart'; @@ -132,6 +134,32 @@ class _EditVideoDialogState extends State { } } + /// Genera un thumbnail automáticamente desde el video si no hay poster + Future _generateThumbnailFromVideo() async { + if (widget.video.fileUrl == null || widget.video.fileUrl!.isEmpty) return; + + try { + // Generar thumbnail desde el video + final thumbnailBytes = await VideoThumbnail.thumbnailData( + video: widget.video.fileUrl!, + imageFormat: ImageFormat.JPEG, + maxWidth: 1280, // Alta calidad para poster + quality: 85, + ); + + if (thumbnailBytes != null && thumbnailBytes.isNotEmpty) { + // Guardar el thumbnail generado como nueva portada (sin mostrar en UI) + newPosterBytes = thumbnailBytes; + newPosterFileName = 'thumbnail_${widget.video.fileName}.jpg'; + + debugPrint('✅ Thumbnail generado automáticamente para edición'); + } + } catch (e) { + debugPrint('⚠️ Error generando thumbnail automático: $e'); + // No es crítico, el video se guardará sin poster + } + } + Future _saveChanges() async { // Actualizar título if (titleController.text != widget.video.title) { @@ -175,6 +203,19 @@ class _EditVideoDialogState extends State { newPosterFileName!, ); } + // Si no hay poster existente y no se seleccionó/eliminó uno, generar automáticamente + else if (widget.video.posterUrl == null || + widget.video.posterUrl!.isEmpty) { + await _generateThumbnailFromVideo(); + // Si se generó thumbnail, subirlo + if (newPosterBytes != null && newPosterFileName != null) { + await widget.provider.updateVideoPoster( + widget.video.mediaFileId, + newPosterBytes!, + newPosterFileName!, + ); + } + } if (!mounted) return; Navigator.pop(context, true); diff --git a/lib/pages/videos/widgets/premium_upload_dialog.dart b/lib/pages/videos/widgets/premium_upload_dialog.dart index d2819ca..0bb0a71 100644 --- a/lib/pages/videos/widgets/premium_upload_dialog.dart +++ b/lib/pages/videos/widgets/premium_upload_dialog.dart @@ -3,6 +3,8 @@ import 'dart:html' as html; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; import 'package:chewie/chewie.dart'; +import 'package:get_thumbnail_video/index.dart'; +import 'package:get_thumbnail_video/video_thumbnail.dart'; import 'package:energy_media/models/media/media_models.dart'; import 'package:energy_media/providers/videos_provider.dart'; import 'package:energy_media/theme/theme.dart'; @@ -130,6 +132,37 @@ class _PremiumUploadDialogState extends State { } } + /// Genera un thumbnail automáticamente desde el video si no se seleccionó poster + Future _generateThumbnailFromVideo() async { + if (_videoBlobUrl == null || selectedVideo == null) return; + + try { + // Generar thumbnail desde el video + final thumbnailBytes = await VideoThumbnail.thumbnailData( + video: _videoBlobUrl!, + imageFormat: ImageFormat.JPEG, + maxWidth: 1280, // Alta calidad para poster + quality: 85, + ); + + if (thumbnailBytes != null && thumbnailBytes.isNotEmpty) { + // Actualizar el provider con el thumbnail generado (sin mostrar en UI) + widget.provider.webPosterBytes = thumbnailBytes; + widget.provider.posterName = + 'thumbnail_${videoFileName ?? 'video'}.jpg'; + widget.provider.posterFileExtension = '.jpg'; + + // NO actualizar selectedPoster ni posterFileName para que no se muestre en UI + // El thumbnail está disponible en el provider para subir automáticamente + + debugPrint('✅ Thumbnail generado automáticamente (oculto en UI)'); + } + } catch (e) { + debugPrint('⚠️ Error generando thumbnail automático: $e'); + // No es crítico, el video se subirá sin poster + } + } + Future _uploadVideo() async { if (titleController.text.isEmpty || selectedVideo == null || @@ -148,6 +181,11 @@ class _PremiumUploadDialogState extends State { setState(() => isUploading = true); + // Si no hay poster seleccionado, generar thumbnail automáticamente desde el video + if (selectedPoster == null && _videoBlobUrl != null) { + await _generateThumbnailFromVideo(); + } + // Procesar tags: separar por comas o espacios List? tags; if (tagsController.text.isNotEmpty) {