thumbails fix

This commit is contained in:
Abraham
2026-01-15 21:34:40 -08:00
parent ec5c62a64b
commit 0b0d9a81e2
3 changed files with 80 additions and 15 deletions

View File

@@ -386,7 +386,7 @@ class _GestorVideosPageState extends State<GestorVideosPage> {
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<GestorVideosPage> {
],
),
),
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,
),
),
),
),
),
],

View File

@@ -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<EditVideoDialog> {
}
}
/// Genera un thumbnail automáticamente desde el video si no hay poster
Future<void> _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<void> _saveChanges() async {
// Actualizar título
if (titleController.text != widget.video.title) {
@@ -175,6 +203,19 @@ class _EditVideoDialogState extends State<EditVideoDialog> {
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);

View File

@@ -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<PremiumUploadDialog> {
}
}
/// Genera un thumbnail automáticamente desde el video si no se seleccionó poster
Future<void> _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<void> _uploadVideo() async {
if (titleController.text.isEmpty ||
selectedVideo == null ||
@@ -148,6 +181,11 @@ class _PremiumUploadDialogState extends State<PremiumUploadDialog> {
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<String>? tags;
if (tagsController.text.isNotEmpty) {