Tags añadidos
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:pluto_grid/pluto_grid.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:nethive_neo/providers/videos_provider.dart';
|
||||
import 'package:nethive_neo/models/media/media_models.dart';
|
||||
import 'package:nethive_neo/theme/theme.dart';
|
||||
@@ -319,6 +321,45 @@ class _GestorVideosPageState extends State<GestorVideosPage> {
|
||||
type: PlutoColumnType.text(),
|
||||
width: 150,
|
||||
),
|
||||
PlutoColumn(
|
||||
title: 'Etiquetas',
|
||||
field: 'tags',
|
||||
type: PlutoColumnType.text(),
|
||||
width: 180,
|
||||
renderer: (rendererContext) {
|
||||
final video =
|
||||
rendererContext.row.cells['video']?.value as MediaFileModel?;
|
||||
if (video == null || video.tags.isEmpty) return const SizedBox();
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
child: Wrap(
|
||||
spacing: 4,
|
||||
runSpacing: 4,
|
||||
children: video.tags.take(3).map((tag) {
|
||||
return Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF4EC9F5), Color(0xFFFFB733)],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
tag,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF0B0B0D),
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
PlutoColumn(
|
||||
title: 'Acciones',
|
||||
field: 'actions',
|
||||
@@ -616,10 +657,14 @@ class _GestorVideosPageState extends State<GestorVideosPage> {
|
||||
final titleController = TextEditingController(text: video.title);
|
||||
final descriptionController =
|
||||
TextEditingController(text: video.fileDescription);
|
||||
final tagsController = TextEditingController(text: video.tags.join(', '));
|
||||
MediaCategoryModel? selectedCategory = provider.categories
|
||||
.where((cat) => cat.mediaCategoriesId == video.mediaCategoryFk)
|
||||
.firstOrNull;
|
||||
|
||||
Uint8List? newPosterBytes;
|
||||
String? newPosterFileName;
|
||||
|
||||
final result = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
@@ -699,6 +744,105 @@ class _GestorVideosPageState extends State<GestorVideosPage> {
|
||||
setDialogState(() => selectedCategory = value);
|
||||
},
|
||||
),
|
||||
const Gap(16),
|
||||
TextFormField(
|
||||
controller: tagsController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Etiquetas (Tags)',
|
||||
hintText: 'Ej: deportes, fútbol, entrenamiento',
|
||||
helperText: 'Separa las etiquetas con comas o espacios',
|
||||
prefixIcon: Icon(
|
||||
Icons.label,
|
||||
color: AppTheme.of(context).primaryColor,
|
||||
),
|
||||
filled: true,
|
||||
fillColor: AppTheme.of(context).tertiaryBackground,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Gap(24),
|
||||
// Sección de portada
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Portada Actual',
|
||||
style: AppTheme.of(context).bodyText1.override(
|
||||
fontFamily: 'Poppins',
|
||||
color: AppTheme.of(context).primaryText,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const Gap(12),
|
||||
if (video.posterUrl != null)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
video.posterUrl!,
|
||||
height: 120,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
)
|
||||
else
|
||||
Container(
|
||||
height: 120,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.of(context).tertiaryBackground,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.video_library,
|
||||
size: 48,
|
||||
color: AppTheme.of(context).secondaryText,
|
||||
),
|
||||
),
|
||||
const Gap(12),
|
||||
ElevatedButton.icon(
|
||||
onPressed: () async {
|
||||
final ImagePicker picker = ImagePicker();
|
||||
final XFile? image = await picker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
maxWidth: 1920,
|
||||
imageQuality: 85,
|
||||
);
|
||||
|
||||
if (image != null) {
|
||||
final bytes = await image.readAsBytes();
|
||||
setDialogState(() {
|
||||
newPosterBytes = bytes;
|
||||
newPosterFileName = image.name;
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.image),
|
||||
label: Text(newPosterBytes != null
|
||||
? 'Portada Seleccionada'
|
||||
: 'Cambiar Portada'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: newPosterBytes != null
|
||||
? AppTheme.of(context).alternate
|
||||
: AppTheme.of(context).primaryColor,
|
||||
foregroundColor: const Color(0xFF0B0B0D),
|
||||
),
|
||||
),
|
||||
if (newPosterBytes != null) ...[
|
||||
const Gap(12),
|
||||
Text(
|
||||
'Nueva portada: $newPosterFileName',
|
||||
style: AppTheme.of(context).bodyText2.override(
|
||||
fontFamily: 'Poppins',
|
||||
color: AppTheme.of(context).alternate,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -739,6 +883,29 @@ class _GestorVideosPageState extends State<GestorVideosPage> {
|
||||
);
|
||||
}
|
||||
|
||||
// Actualizar tags
|
||||
final newTags = tagsController.text
|
||||
.split(RegExp(r'[,\s]+'))
|
||||
.map((tag) => tag.trim())
|
||||
.where((tag) => tag.isNotEmpty)
|
||||
.toList();
|
||||
|
||||
if (newTags.join(',') != video.tags.join(',')) {
|
||||
await provider.updateVideoTags(
|
||||
video.mediaFileId,
|
||||
newTags,
|
||||
);
|
||||
}
|
||||
|
||||
// Actualizar portada si se seleccionó una nueva
|
||||
if (newPosterBytes != null && newPosterFileName != null) {
|
||||
await provider.updateVideoPoster(
|
||||
video.mediaFileId,
|
||||
newPosterBytes!,
|
||||
newPosterFileName!,
|
||||
);
|
||||
}
|
||||
|
||||
Navigator.pop(context, true);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
|
||||
Reference in New Issue
Block a user