modificacion de colores en el login

This commit is contained in:
Abraham
2026-01-13 15:44:45 -08:00
parent 9533b60906
commit 7bdb9a2d74
6 changed files with 236 additions and 32 deletions

View File

@@ -232,7 +232,7 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
flex: 1, flex: 1,
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFF0F172A), color: const Color.fromARGB(255, 25, 26, 28),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.1), color: Colors.black.withOpacity(0.1),
@@ -278,13 +278,11 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
colors: [ colors: [
Color(0xFF4EC9F5), // Cyan principal Color(0xFF42BCEE),
Color(0xFFFFB733), // Yellow Color(0xFF5865B5),
Color(0xFF6B2F8A), // Purple Color(0xFF653093)
Color(0xFFFF7A3D), // Orange
Color(0xFF4EC9F5), // Cyan de vuelta
], ],
stops: [0.0, 0.25, 0.5, 0.75, 1.0], stops: [0.25, 0.5, 1.0],
), ),
), ),
child: Stack( child: Stack(

View File

@@ -250,7 +250,7 @@ class _LoginFormState extends State<LoginForm> with TickerProviderStateMixin {
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide( borderSide: const BorderSide(
color: Color(0xFF10B981), color: Color(0xFF4EC9F5),
width: 2, width: 2,
), ),
), ),

View File

@@ -364,6 +364,7 @@ class _GestorVideosPageState extends State<GestorVideosPage> {
: (video.fileUrl != null && video.fileUrl!.isNotEmpty) : (video.fileUrl != null && video.fileUrl!.isNotEmpty)
? VideoThumbnailWidget( ? VideoThumbnailWidget(
videoUrl: video.fileUrl!, videoUrl: video.fileUrl!,
height: 100,
fit: BoxFit.cover, fit: BoxFit.cover,
) )
: _buildThumbnailPlaceholder(), : _buildThumbnailPlaceholder(),

View File

@@ -206,7 +206,7 @@ class _VideosLayoutState extends State<VideosLayout> {
colors: [ colors: [
Color(0xFF42BCEE), Color(0xFF42BCEE),
Color(0xFF5865B5), Color(0xFF5865B5),
Color(0xFF653093), Color(0xFF653093)
], ],
stops: const [0.0, 0.5, 1.0], stops: const [0.0, 0.5, 1.0],
), ),

View File

@@ -42,6 +42,7 @@ class _EditVideoDialogState extends State<EditVideoDialog> {
late TextEditingController tagsController; late TextEditingController tagsController;
Uint8List? newPosterBytes; Uint8List? newPosterBytes;
String? newPosterFileName; String? newPosterFileName;
bool _deletePoster = false;
VideoPlayerController? _videoPlayerController; VideoPlayerController? _videoPlayerController;
ChewieController? _chewieController; ChewieController? _chewieController;
bool _isVideoLoading = false; bool _isVideoLoading = false;
@@ -162,8 +163,12 @@ class _EditVideoDialogState extends State<EditVideoDialog> {
); );
} }
// Actualizar portada si se seleccionó una nueva // Eliminar portada si se solicitó
if (newPosterBytes != null && newPosterFileName != null) { if (_deletePoster) {
await widget.provider.deletePoster(widget.video.mediaFileId);
}
// Actualizar portada si se seleccionó una nueva (solo si no se eliminó)
else if (newPosterBytes != null && newPosterFileName != null) {
await widget.provider.updateVideoPoster( await widget.provider.updateVideoPoster(
widget.video.mediaFileId, widget.video.mediaFileId,
newPosterBytes!, newPosterBytes!,
@@ -437,10 +442,100 @@ class _EditVideoDialogState extends State<EditVideoDialog> {
} }
Widget _buildPosterSection() { Widget _buildPosterSection() {
final hasPoster = widget.video.posterUrl != null && !_deletePoster;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (widget.video.posterUrl != null) if (_deletePoster)
Container(
height: 140,
width: double.infinity,
decoration: BoxDecoration(
color: AppTheme.of(context).tertiaryBackground,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xFFFF2D2D).withOpacity(0.3),
width: 2,
),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.delete_outline,
size: 48,
color: const Color(0xFFFF2D2D).withOpacity(0.7),
),
const Gap(8),
Text(
'Portada marcada para eliminar',
style: AppTheme.of(context).bodyText2.override(
fontFamily: 'Poppins',
color: const Color(0xFFFF2D2D),
fontSize: 12,
),
),
],
),
),
)
else if (newPosterBytes != null)
// Mostrar preview de nueva portada seleccionada
Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.memory(
newPosterBytes!,
height: 140,
width: double.infinity,
fit: BoxFit.cover,
),
),
Positioned(
top: 8,
right: 8,
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: AppTheme.of(context).success,
borderRadius: BorderRadius.circular(6),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.fiber_new,
size: 14,
color: Colors.white,
),
const Gap(4),
Text(
'Nueva',
style: AppTheme.of(context).bodyText2.override(
fontFamily: 'Poppins',
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
],
)
else if (hasPoster)
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
child: Image.network( child: Image.network(
@@ -458,30 +553,89 @@ class _EditVideoDialogState extends State<EditVideoDialog> {
color: AppTheme.of(context).tertiaryBackground, color: AppTheme.of(context).tertiaryBackground,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Icon( child: Column(
Icons.image, mainAxisAlignment: MainAxisAlignment.center,
size: 48, children: [
color: AppTheme.of(context).tertiaryText, Icon(
Icons.video_library,
size: 48,
color: AppTheme.of(context).tertiaryText,
),
const Gap(8),
Text(
'Sin portada',
style: AppTheme.of(context).bodyText2.override(
fontFamily: 'Poppins',
color: AppTheme.of(context).tertiaryText,
fontSize: 12,
),
),
],
), ),
), ),
const Gap(12), const Gap(12),
ElevatedButton.icon( Row(
onPressed: _selectPoster, children: [
icon: const Icon(Icons.image, size: 18), Expanded(
label: Text( child: ElevatedButton.icon(
newPosterBytes != null ? 'Portada Seleccionada' : 'Cambiar Portada', onPressed: _deletePoster ? null : _selectPoster,
), icon: const Icon(Icons.image, size: 18),
style: ElevatedButton.styleFrom( label: Text(
backgroundColor: newPosterBytes != null newPosterBytes != null
? AppTheme.of(context).success ? 'Portada Seleccionada'
: AppTheme.of(context).primaryColor, : 'Cambiar Portada',
foregroundColor: Colors.white, ),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder( backgroundColor: newPosterBytes != null
borderRadius: BorderRadius.circular(10), ? AppTheme.of(context).success
: AppTheme.of(context).primaryColor,
foregroundColor: Colors.white,
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0,
disabledBackgroundColor:
AppTheme.of(context).tertiaryText.withOpacity(0.3),
),
),
), ),
elevation: 0, if (hasPoster || _deletePoster) ...[
), const Gap(8),
ElevatedButton.icon(
onPressed: () {
setState(() {
_deletePoster = !_deletePoster;
if (_deletePoster) {
// Si se marca para eliminar, limpiar nueva portada seleccionada
newPosterBytes = null;
newPosterFileName = null;
}
});
},
icon: Icon(
_deletePoster ? Icons.undo : Icons.delete_outline,
size: 18,
),
label: Text(
_deletePoster ? 'Deshacer' : 'Eliminar',
),
style: ElevatedButton.styleFrom(
backgroundColor: _deletePoster
? AppTheme.of(context).warning
: const Color(0xFFFF2D2D),
foregroundColor: Colors.white,
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0,
),
),
],
],
), ),
if (newPosterBytes != null) ...[ if (newPosterBytes != null) ...[
const Gap(8), const Gap(8),

View File

@@ -580,6 +580,57 @@ class VideosProvider extends ChangeNotifier {
} }
} }
/// Delete video poster only (not the video itself)
Future<bool> deletePoster(int mediaFileId) async {
try {
isLoading = true;
notifyListeners();
// Get current metadata
final response = await supabaseML
.from('media_files')
.select('metadata_json')
.eq('media_file_id', mediaFileId)
.eq('organization_fk', organizationId)
.single();
final metadata = response['metadata_json'] as Map<String, dynamic>? ?? {};
final posterUrl = metadata['poster_url'] as String?;
// Delete poster from storage if exists
if (posterUrl != null && posterUrl.isNotEmpty) {
try {
final uri = Uri.parse(posterUrl);
final pathSegments = uri.pathSegments;
final bucketIndex = pathSegments.indexOf('energymedia');
if (bucketIndex != -1 && bucketIndex < pathSegments.length - 1) {
final posterPath = pathSegments.sublist(bucketIndex + 1).join('/');
await supabaseML.storage.from('energymedia').remove([posterPath]);
}
} catch (e) {
print('Error eliminando poster del storage: $e');
}
}
// Remove poster references from metadata
metadata.remove('poster_url');
metadata.remove('poster_file_name');
// Update metadata
await updateVideoMetadata(mediaFileId, metadata);
isLoading = false;
notifyListeners();
return true;
} catch (e) {
errorMessage = 'Error eliminando portada: $e';
isLoading = false;
notifyListeners();
print('Error en deletePoster: $e');
return false;
}
}
// ========== DELETE METHODS ========== // ========== DELETE METHODS ==========
/// Delete video and its storage files /// Delete video and its storage files