diff --git a/lib/app.dart b/lib/app.dart index dacd5a7..8986641 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -14,6 +14,7 @@ import 'package:notas/screens/biometric_gate_screen.dart'; import 'package:notas/screens/home_screen.dart'; import 'package:notas/screens/settings_screen.dart'; import 'package:notas/screens/vault_access_screen.dart'; +import 'package:notas/theme/app_colors.dart'; import 'package:notas/theme/app_theme.dart'; import 'package:notas/widgets/sync_status.dart'; import 'package:path/path.dart' as p; @@ -68,7 +69,7 @@ class _NotesAppState extends State String? _syncErrorMessage; int _syncOperationId = 0; int _homeRefreshToken = 0; - Color _themeSeedColor = Colors.amber; + Color _themeSeedColor = AppColors.defaultThemeSeedColor; @override void initState() { @@ -859,15 +860,7 @@ class _NotesAppState extends State child: Scaffold( body: Container( decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF191A1D), - Color(0xFF222326), - Color(0xFF101114), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), + gradient: AppColors.backdropGradient, ), child: SafeArea( child: Column( diff --git a/lib/screens/biometric_choice_screen.dart b/lib/screens/biometric_choice_screen.dart index d57e3bd..7c679ce 100644 --- a/lib/screens/biometric_choice_screen.dart +++ b/lib/screens/biometric_choice_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:notas/theme/app_colors.dart'; class BiometricChoiceScreen extends StatelessWidget { const BiometricChoiceScreen({ @@ -16,17 +17,7 @@ class BiometricChoiceScreen extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( body: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF191A1D), - Color(0xFF222326), - Color(0xFF101114), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), + decoration: const BoxDecoration(gradient: AppColors.backdropGradient), child: SafeArea( child: Column( children: [ @@ -39,12 +30,12 @@ class BiometricChoiceScreen extends StatelessWidget { child: Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( - color: const Color(0xFF1D1E20), + color: AppColors.surface, borderRadius: BorderRadius.circular(24), - border: Border.all(color: Colors.white.withValues(alpha: 0.08)), + border: Border.all(color: AppColors.borderMuted), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: 0.35), + color: AppColors.shadow, blurRadius: 30, offset: const Offset(0, 18), ), @@ -64,7 +55,7 @@ class BiometricChoiceScreen extends StatelessWidget { 'Proteger con huella', textAlign: TextAlign.center, style: TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 28, fontWeight: FontWeight.w700, ), @@ -74,7 +65,7 @@ class BiometricChoiceScreen extends StatelessWidget { '¿Quieres que la app te pida huella o cara antes de entrar a tus notas?', textAlign: TextAlign.center, style: TextStyle( - color: Colors.white.withValues(alpha: 0.72), + color: AppColors.textSecondary, height: 1.4, ), ), @@ -82,13 +73,17 @@ class BiometricChoiceScreen extends StatelessWidget { FilledButton( onPressed: isBusy ? null : onEnableBiometrics, style: FilledButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), + padding: const EdgeInsets.symmetric( + vertical: 14, + ), ), child: isBusy ? const SizedBox( width: 18, height: 18, - child: CircularProgressIndicator(strokeWidth: 2), + child: CircularProgressIndicator( + strokeWidth: 2, + ), ) : const Text('Sí, activar huella'), ), @@ -96,9 +91,13 @@ class BiometricChoiceScreen extends StatelessWidget { OutlinedButton( onPressed: isBusy ? null : onSkipBiometrics, style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), - side: const BorderSide(color: Colors.white24), - foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + vertical: 14, + ), + side: const BorderSide( + color: AppColors.textDisabled, + ), + foregroundColor: AppColors.textPrimary, ), child: const Text('No, entrar sin huella'), ), diff --git a/lib/screens/biometric_gate_screen.dart b/lib/screens/biometric_gate_screen.dart index 13975a8..c26e490 100644 --- a/lib/screens/biometric_gate_screen.dart +++ b/lib/screens/biometric_gate_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:notas/theme/app_colors.dart'; class BiometricGateScreen extends StatefulWidget { const BiometricGateScreen({ @@ -40,17 +41,7 @@ class _BiometricGateScreenState extends State { Widget build(BuildContext context) { return Scaffold( body: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF191A1D), - Color(0xFF222326), - Color(0xFF101114), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), + decoration: const BoxDecoration(gradient: AppColors.backdropGradient), child: SafeArea( child: Column( children: [ @@ -63,12 +54,12 @@ class _BiometricGateScreenState extends State { child: Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( - color: const Color(0xFF1D1E20), + color: AppColors.surface, borderRadius: BorderRadius.circular(24), - border: Border.all(color: Colors.white.withValues(alpha: 0.08)), + border: Border.all(color: AppColors.borderMuted), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: 0.35), + color: AppColors.shadow, blurRadius: 30, offset: const Offset(0, 18), ), @@ -88,7 +79,7 @@ class _BiometricGateScreenState extends State { 'Desbloqueo biométrico', textAlign: TextAlign.center, style: TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 28, fontWeight: FontWeight.w700, ), @@ -98,21 +89,27 @@ class _BiometricGateScreenState extends State { 'Pon tu huella o cara para entrar a tus notas.', textAlign: TextAlign.center, style: TextStyle( - color: Colors.white.withValues(alpha: 0.72), + color: AppColors.textSecondary, height: 1.4, ), ), const SizedBox(height: 22), FilledButton( - onPressed: widget.isBusy ? null : widget.onUnlockRequested, + onPressed: widget.isBusy + ? null + : widget.onUnlockRequested, style: FilledButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), + padding: const EdgeInsets.symmetric( + vertical: 14, + ), ), child: widget.isBusy ? const SizedBox( width: 18, height: 18, - child: CircularProgressIndicator(strokeWidth: 2), + child: CircularProgressIndicator( + strokeWidth: 2, + ), ) : const Text('Desbloquear'), ), diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 4ee103f..6f07984 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -15,6 +15,7 @@ import 'package:notas/widgets/note_card.dart'; import 'package:notas/widgets/search_app_bar.dart'; import 'package:notas/widgets/sync_status.dart'; import 'package:notas/widgets/sync_status_indicator.dart'; +import 'package:notas/theme/app_colors.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({ @@ -490,13 +491,7 @@ class _HomeScreenState extends State { return Scaffold( body: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF191A1D), Color(0xFF222326), Color(0xFF101114)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), + decoration: const BoxDecoration(gradient: AppColors.backdropGradient), child: SafeArea( child: Column( children: [ @@ -570,7 +565,7 @@ class _HomeScreenState extends State { child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: _closeMenu, - child: Container(color: Colors.black), + child: Container(color: AppColors.overlay), ), ), ), @@ -583,7 +578,7 @@ class _HomeScreenState extends State { bottom: 0, width: 280, child: Material( - color: const Color.fromRGBO(24, 25, 26, 1), + color: AppColors.cardBackground, elevation: 8, child: MenuDrawer( onMenuItemTapped: _handleMenuItemTapped, @@ -651,7 +646,7 @@ class _DraggableNote extends StatelessWidget { return MouseRegion( cursor: SystemMouseCursors.grabbing, child: Material( - color: Colors.transparent, + color: AppColors.transparent, elevation: 8, child: SizedBox( width: cellWidth, @@ -689,9 +684,12 @@ class _DraggableNote extends StatelessWidget { child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: const Color.fromRGBO(24, 25, 26, 1), + color: AppColors.cardBackground, borderRadius: BorderRadius.circular(12), - border: Border.all(color: borderColor ?? Colors.white24, width: 1), + border: Border.all( + color: borderColor ?? AppColors.textDisabled, + width: 1, + ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -700,7 +698,7 @@ class _DraggableNote extends StatelessWidget { Text( note.title, style: const TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -710,7 +708,10 @@ class _DraggableNote extends StatelessWidget { const SizedBox(height: 8), Text( note.body, - style: const TextStyle(color: Colors.white70, fontSize: 14), + style: const TextStyle( + color: AppColors.textSecondary, + fontSize: 14, + ), maxLines: 20, overflow: TextOverflow.clip, ), @@ -726,7 +727,7 @@ class _DraggableNote extends StatelessWidget { final Widget content = Container( decoration: BoxDecoration( border: isDragTargetActive - ? Border.all(color: Colors.blue.shade400, width: 2) + ? Border.all(color: AppColors.dragTargetBorder, width: 2) : null, borderRadius: BorderRadius.circular(12), ), @@ -781,7 +782,11 @@ class _EmptyState extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.note_add_outlined, color: Colors.white54, size: 48), + const Icon( + Icons.note_add_outlined, + color: AppColors.textMuted, + size: 48, + ), const SizedBox(height: 12), Text( searchQuery != null && searchQuery!.isNotEmpty @@ -792,7 +797,7 @@ class _EmptyState extends StatelessWidget { ? 'No hay notas en esta categoría' : 'Aún no hay notas', style: const TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 18, fontWeight: FontWeight.w600, ), @@ -807,7 +812,7 @@ class _EmptyState extends StatelessWidget { ? 'Pulsa el botón + para crear una nota en “$categoryName”.' : 'Pulsa el botón + para crear la primera.', textAlign: TextAlign.center, - style: const TextStyle(color: Colors.white70), + style: const TextStyle(color: AppColors.textSecondary), ), ], ), @@ -1000,9 +1005,9 @@ class _CategoryDialogState extends State<_CategoryDialog> { const SizedBox(height: 16), Container( decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.04), + color: AppColors.fill, borderRadius: BorderRadius.circular(14), - border: Border.all(color: Colors.white12), + border: Border.all(color: AppColors.border), ), child: Column( mainAxisSize: MainAxisSize.min, @@ -1031,7 +1036,7 @@ class _CategoryDialogState extends State<_CategoryDialog> { ), ], ), - const Divider(height: 1, color: Colors.white12), + const Divider(height: 1, color: AppColors.border), Padding( padding: const EdgeInsets.all(12), child: AnimatedSwitcher( @@ -1057,11 +1062,11 @@ class _CategoryDialogState extends State<_CategoryDialog> { borderRadius: BorderRadius.circular(10), border: isSelected ? Border.all( - color: Colors.white, + color: AppColors.textPrimary, width: 2, ) : Border.all( - color: Colors.white12, + color: AppColors.border, width: 1, ), ), @@ -1087,21 +1092,21 @@ class _CategoryDialogState extends State<_CategoryDialog> { height: 42, decoration: BoxDecoration( color: isSelected - ? Colors.white10 - : Colors.transparent, + ? AppColors.hover + : AppColors.transparent, borderRadius: BorderRadius.circular(10), border: Border.all( color: isSelected - ? Colors.white - : Colors.white12, + ? AppColors.textPrimary + : AppColors.border, width: 1, ), ), child: Icon( icon, color: isSelected - ? Colors.white - : Colors.white70, + ? AppColors.textPrimary + : AppColors.textSecondary, ), ), ); @@ -1119,7 +1124,10 @@ class _CategoryDialogState extends State<_CategoryDialog> { if (widget.category != null) TextButton( onPressed: _deleteCategory, - child: const Text('Borrar', style: TextStyle(color: Colors.red)), + child: const Text( + 'Borrar', + style: TextStyle(color: AppColors.destructive), + ), ), TextButton( onPressed: () => Navigator.pop(context), @@ -1158,7 +1166,7 @@ class _PickerTabButton extends StatelessWidget { return Material( borderRadius: borderRadius, clipBehavior: Clip.antiAlias, - color: selected ? Colors.white10 : Colors.transparent, + color: selected ? AppColors.hover : AppColors.transparent, child: InkWell( borderRadius: borderRadius, onTap: onTap, @@ -1168,7 +1176,7 @@ class _PickerTabButton extends StatelessWidget { child: Text( label, style: TextStyle( - color: selected ? Colors.white : Colors.white54, + color: selected ? AppColors.textPrimary : AppColors.textMuted, fontWeight: selected ? FontWeight.w600 : FontWeight.w400, ), ), diff --git a/lib/screens/note_editor_screen.dart b/lib/screens/note_editor_screen.dart index e418d0a..3c6c38c 100644 --- a/lib/screens/note_editor_screen.dart +++ b/lib/screens/note_editor_screen.dart @@ -7,6 +7,7 @@ import 'package:intl/intl.dart'; import 'package:notas/models/category.dart'; import 'package:notas/models/note.dart'; import 'package:notas/platform/app_platform.dart'; +import 'package:notas/theme/app_colors.dart'; import 'package:notas/widgets/category_style.dart'; // NoteEditorScreen: unified UI for creating and editing notes. @@ -41,7 +42,7 @@ class NoteEditorScreen extends StatefulWidget { return showGeneralDialog( context: context, barrierDismissible: false, - barrierColor: Colors.transparent, + barrierColor: AppColors.transparent, transitionDuration: const Duration(milliseconds: 200), pageBuilder: (context, animation, secondaryAnimation) { return NoteEditorScreen( @@ -201,30 +202,30 @@ class _NoteEditorScreenState extends State { final bool isDeletedNote = _currentNote.isDeleted; return AlertDialog( - backgroundColor: const Color(0xFF303134), + backgroundColor: AppColors.surfaceElevated, title: Text( isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar nota', - style: const TextStyle(color: Colors.white), + style: const TextStyle(color: AppColors.textPrimary), ), content: Text( isDeletedNote ? 'Esta nota ya está borrada. Si la eliminas ahora, se borrará permanentemente.' : '¿Estás seguro de que deseas eliminar esta nota?', - style: const TextStyle(color: Colors.white70), + style: const TextStyle(color: AppColors.textSecondary), ), actions: [ TextButton( onPressed: () => onConfirmed(false), child: const Text( 'Cancelar', - style: TextStyle(color: Colors.white70), + style: TextStyle(color: AppColors.textSecondary), ), ), TextButton( onPressed: () => onConfirmed(true), child: Text( isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar', - style: const TextStyle(color: Colors.red), + style: const TextStyle(color: AppColors.destructive), ), ), ], @@ -236,7 +237,7 @@ class _NoteEditorScreenState extends State { final bool? confirmed = await showDialog( context: context, barrierDismissible: false, - barrierColor: Colors.transparent, + barrierColor: AppColors.transparent, builder: (BuildContext dialogContext) { return _buildDeleteConfirmationDialog( onConfirmed: (bool confirmed) => @@ -253,7 +254,7 @@ class _NoteEditorScreenState extends State { final bool? confirmed = await showDialog( context: context, barrierDismissible: false, - barrierColor: Colors.transparent, + barrierColor: AppColors.transparent, builder: (BuildContext dialogContext) { return _buildDeleteConfirmationDialog( onConfirmed: (bool confirmed) => @@ -282,13 +283,13 @@ class _NoteEditorScreenState extends State { }; return Material( - color: Colors.transparent, + color: AppColors.transparent, child: Stack( children: [ const Positioned.fill( child: ModalBarrier( dismissible: false, - color: Color.fromARGB(140, 0, 0, 0), + color: AppColors.overlay, ), ), Center( @@ -319,7 +320,7 @@ class _NoteEditorScreenState extends State { Color _categoryBackgroundColor(Category? category) { if (category?.colorValue == null) { - return Colors.white.withValues(alpha: 0.08); + return AppColors.borderMuted; } return Color(category!.colorValue!); @@ -327,11 +328,13 @@ class _NoteEditorScreenState extends State { Color _categoryForegroundColor(Category? category) { if (category == null || category.colorValue == null) { - return Colors.white; + return AppColors.textPrimary; } final Color background = Color(category.colorValue!); - return background.computeLuminance() > 0.55 ? Colors.black87 : Colors.white; + return background.computeLuminance() > 0.55 + ? AppColors.textOnSurfaceDark + : AppColors.textPrimary; } Widget _buildCategorySelectorBox({Category? category}) { @@ -351,7 +354,7 @@ class _NoteEditorScreenState extends State { border: Border.all( color: category?.colorValue != null ? backgroundColor.withValues(alpha: 0.85) - : Colors.white24, + : AppColors.textDisabled, ), ), child: Row( @@ -407,7 +410,7 @@ class _NoteEditorScreenState extends State { final double menuHeight = math.min(screenSize.height - 32, 360); return Material( - color: Colors.transparent, + color: AppColors.transparent, child: Stack( children: [ Positioned.fill( @@ -425,7 +428,7 @@ class _NoteEditorScreenState extends State { ), child: Material( elevation: 10, - color: const Color(0xFF303134), + color: AppColors.surfaceElevated, borderRadius: BorderRadius.circular(12), clipBehavior: Clip.antiAlias, child: ListView( @@ -485,7 +488,7 @@ class _NoteEditorScreenState extends State { onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), - color: isSelected ? Colors.white.withValues(alpha: 0.08) : null, + color: isSelected ? AppColors.hover : null, child: Row( children: [ Container( @@ -497,7 +500,7 @@ class _NoteEditorScreenState extends State { border: Border.all( color: category?.colorValue != null ? backgroundColor.withValues(alpha: 0.85) - : Colors.white24, + : AppColors.textDisabled, ), ), child: Icon(icon, size: 16, color: foregroundColor), @@ -553,13 +556,15 @@ class _NoteEditorScreenState extends State { Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.white12, width: 1)), + border: Border( + bottom: BorderSide(color: AppColors.border, width: 1), + ), ), child: Row( children: [ IconButton( onPressed: _closeWithoutSaving, - icon: const Icon(Icons.close, color: Colors.white70), + icon: const Icon(Icons.close, color: AppColors.textSecondary), tooltip: 'Cerrar sin guardar', ), const SizedBox(width: 8), @@ -571,14 +576,14 @@ class _NoteEditorScreenState extends State { Text( 'Posicion: ${_currentNote.position}', style: const TextStyle( - color: Colors.white54, + color: AppColors.textMuted, fontSize: 12, ), ), Text( 'Creado: ${_formatDate(_currentNote.createdAt)}', style: const TextStyle( - color: Colors.white54, + color: AppColors.textMuted, fontSize: 12, ), ), @@ -586,7 +591,7 @@ class _NoteEditorScreenState extends State { Text( 'Modificado: ${_formatDate(_currentNote.updatedAt)}', style: const TextStyle( - color: Colors.white54, + color: AppColors.textMuted, fontSize: 12, ), ), @@ -621,13 +626,13 @@ class _NoteEditorScreenState extends State { TextField( controller: _titleController, style: const TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 28, fontWeight: FontWeight.bold, ), decoration: const InputDecoration( hintText: 'Título', - hintStyle: TextStyle(color: Colors.white30), + hintStyle: TextStyle(color: AppColors.textHint), border: InputBorder.none, contentPadding: EdgeInsets.zero, ), @@ -640,13 +645,13 @@ class _NoteEditorScreenState extends State { maxLines: null, expands: true, style: const TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 16, height: 1.6, ), decoration: const InputDecoration( hintText: 'Escribe tu nota...', - hintStyle: TextStyle(color: Colors.white30), + hintStyle: TextStyle(color: AppColors.textHint), border: InputBorder.none, contentPadding: EdgeInsets.zero, ), @@ -659,7 +664,7 @@ class _NoteEditorScreenState extends State { Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( - border: Border(top: BorderSide(color: Colors.white12, width: 1)), + border: Border(top: BorderSide(color: AppColors.border, width: 1)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -667,7 +672,10 @@ class _NoteEditorScreenState extends State { if (!_isNewNote) IconButton( onPressed: _deleteNote, - icon: const Icon(Icons.delete_outline, color: Colors.red), + icon: const Icon( + Icons.delete_outline, + color: AppColors.destructive, + ), tooltip: 'Eliminar nota', ) else @@ -684,10 +692,10 @@ class _NoteEditorScreenState extends State { Widget build(BuildContext context) { if (_isMobileLayout) { return Material( - color: Colors.transparent, + color: AppColors.transparent, child: SafeArea( child: Container( - color: const Color.fromARGB(255, 24, 25, 26), + color: AppColors.cardBackground, child: _buildEditorContent(isMobile: true), ), ), @@ -704,7 +712,7 @@ class _NoteEditorScreenState extends State { Positioned.fill( child: ModalBarrier( dismissible: false, - color: const Color.fromARGB(54, 0, 0, 0).withValues(alpha: 0.5), + color: AppColors.shadowDim, ), ), Positioned.fill( @@ -713,10 +721,10 @@ class _NoteEditorScreenState extends State { width: maxWidth, height: maxHeight, child: Material( - color: const Color.fromRGBO(24, 25, 26, 1), + color: AppColors.cardBackground, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), - side: BorderSide(color: Colors.white24, width: 1), + side: BorderSide(color: AppColors.textDisabled, width: 1), ), clipBehavior: Clip.antiAlias, child: _buildEditorContent(isMobile: false), diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 28fb2f0..97df491 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:notas/data/local_vault_service.dart'; +import 'package:notas/theme/app_colors.dart'; import 'package:notas/widgets/search_app_bar.dart'; import 'package:notas/data/api_client.dart'; @@ -29,30 +30,35 @@ class _SettingsScreenState extends State { bool _isServerDeleting = false; bool _isThemeSaving = false; final TextEditingController _endpointController = TextEditingController(); - final TextEditingController _encryptionKeyController = TextEditingController(); + final TextEditingController _encryptionKeyController = + TextEditingController(); bool _endpointLoading = true; bool _encryptionKeyLoading = false; bool _encryptionKeyVisible = false; late Color _selectedSeedColor; - static const List _themeColorOptions = [ - Colors.amber, - Colors.blue, - Colors.teal, - Colors.green, - Colors.pink, - Colors.purple, - ]; + static const List _themeColorOptions = AppColors.themeSeedColors; Future _confirmAndDeleteAll() async { final bool? confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Borrar todos los datos'), - content: const Text('¿Estás seguro? Esta acción eliminará la base de datos local y la clave de cifrado. Asegúrate de tener una copia de seguridad si es necesario o cuenta sincronizada.'), + content: const Text( + '¿Estás seguro? Esta acción eliminará la base de datos local y la clave de cifrado. Asegúrate de tener una copia de seguridad si es necesario o cuenta sincronizada.', + ), actions: [ - TextButton(onPressed: () => Navigator.of(context).pop(false), child: const Text('Cancelar')), - TextButton(onPressed: () => Navigator.of(context).pop(true), child: const Text('Borrar', style: TextStyle(color: Colors.red))), + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Cancelar'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: const Text( + 'Borrar', + style: TextStyle(color: AppColors.destructive), + ), + ), ], ), ); @@ -69,7 +75,9 @@ class _SettingsScreenState extends State { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Todos los datos locales han sido eliminados.')), + const SnackBar( + content: Text('Todos los datos locales han sido eliminados.'), + ), ); } catch (error) { if (!mounted) return; @@ -101,7 +109,7 @@ class _SettingsScreenState extends State { onPressed: () => Navigator.of(context).pop(true), child: const Text( 'Borrar', - style: TextStyle(color: Colors.red), + style: TextStyle(color: AppColors.destructive), ), ), ], @@ -115,11 +123,13 @@ class _SettingsScreenState extends State { }); try { - final Map response = - await AuthApi.instance.deleteAllServerData(); + final Map response = await AuthApi.instance + .deleteAllServerData(); if (response['error'] == true) { - throw Exception(response['body'] ?? response['message'] ?? 'Error desconocido'); + throw Exception( + response['body'] ?? response['message'] ?? 'Error desconocido', + ); } await AuthApi.instance.clearTokens(); @@ -127,7 +137,9 @@ class _SettingsScreenState extends State { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Toda la información del servidor ha sido eliminada.')), + const SnackBar( + content: Text('Toda la información del servidor ha sido eliminada.'), + ), ); } catch (error) { if (!mounted) return; @@ -239,7 +251,8 @@ class _SettingsScreenState extends State { }); try { - final String? encryptionKey = await LocalVaultService.instance.readEncryptionKey(); + final String? encryptionKey = await LocalVaultService.instance + .readEncryptionKey(); if (!mounted) return; @@ -286,8 +299,8 @@ class _SettingsScreenState extends State { }) { return ElevatedButton.icon( style: ElevatedButton.styleFrom( - backgroundColor: Colors.redAccent, - foregroundColor: Colors.white, + backgroundColor: AppColors.destructiveAccent, + foregroundColor: AppColors.textPrimary, textStyle: const TextStyle(fontWeight: FontWeight.w600), ), onPressed: onPressed, @@ -306,8 +319,8 @@ class _SettingsScreenState extends State { final bool isSelected = _selectedSeedColor.value == color.value; final Color foregroundColor = ThemeData.estimateBrightnessForColor(color) == Brightness.dark - ? Colors.white - : Colors.black; + ? AppColors.textPrimary + : AppColors.textOnAccent; return Semantics( button: true, @@ -326,12 +339,14 @@ class _SettingsScreenState extends State { color: color, borderRadius: BorderRadius.circular(12), border: Border.all( - color: isSelected ? Colors.white : Colors.white24, + color: isSelected + ? AppColors.textPrimary + : AppColors.textDisabled, width: isSelected ? 2.5 : 1.2, ), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: 0.25), + color: AppColors.shadowSoft, blurRadius: 8, offset: const Offset(0, 3), ), @@ -341,11 +356,7 @@ class _SettingsScreenState extends State { alignment: Alignment.center, children: [ if (isSelected) - Icon( - Icons.check, - size: 22, - color: foregroundColor, - ), + Icon(Icons.check, size: 22, color: foregroundColor), ], ), ), @@ -366,10 +377,14 @@ class _SettingsScreenState extends State { try { await ApiConfig.setEndpoint(value); if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Endpoint guardado'))); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Endpoint guardado'))); } catch (e) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Error guardando endpoint: $e'))); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Error guardando endpoint: $e'))); } } @@ -378,7 +393,9 @@ class _SettingsScreenState extends State { final String endpoint = await ApiConfig.getEndpoint(); if (!mounted) return; _endpointController.text = endpoint; - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Endpoint restaurado al valor por defecto'))); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Endpoint restaurado al valor por defecto')), + ); } Widget _buildResponsiveInputActionsRow({ @@ -433,17 +450,7 @@ class _SettingsScreenState extends State { Widget build(BuildContext context) { return Scaffold( body: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF191A1D), - Color(0xFF222326), - Color(0xFF101114), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), + decoration: const BoxDecoration(gradient: AppColors.backdropGradient), child: SafeArea( child: Column( children: [ @@ -462,9 +469,7 @@ class _SettingsScreenState extends State { children: [ Row( children: [ - const Expanded( - child: Text('Borrar datos locales:'), - ), + const Expanded(child: Text('Borrar datos locales:')), _buildDestructiveButton( label: 'Borrar', onPressed: (_isBusy || _isServerDeleting) @@ -483,7 +488,8 @@ class _SettingsScreenState extends State { ), _buildDestructiveButton( label: 'Borrar', - onPressed: (_isBusy || _isSyncing || _isServerDeleting) + onPressed: + (_isBusy || _isSyncing || _isServerDeleting) ? null : _confirmAndDeleteServerData, isLoading: _isServerDeleting, @@ -498,14 +504,17 @@ class _SettingsScreenState extends State { child: Text('Forzar sincronizacion total:'), ), ElevatedButton.icon( - onPressed: (_isBusy || _isSyncing || _isServerDeleting) + onPressed: + (_isBusy || _isSyncing || _isServerDeleting) ? null : _forceSync, icon: _isSyncing ? const SizedBox( width: 16, height: 16, - child: CircularProgressIndicator(strokeWidth: 2), + child: CircularProgressIndicator( + strokeWidth: 2, + ), ) : const Icon(Icons.sync), label: const Text('Sincronizar'), @@ -524,31 +533,49 @@ class _SettingsScreenState extends State { ], ), const SizedBox(height: 24), - const Text('API endpoint (ej: https://notas-api.lpncnd.es/api)'), + const Text( + 'API endpoint (ej: https://notas-api.lpncnd.es/api)', + ), const SizedBox(height: 8), _buildResponsiveInputActionsRow( input: _endpointLoading - ? const SizedBox(height: 48, child: Center(child: CircularProgressIndicator())) + ? const SizedBox( + height: 48, + child: Center( + child: CircularProgressIndicator(), + ), + ) : TextField( controller: _endpointController, - style: const TextStyle(color: Colors.white), + style: const TextStyle( + color: AppColors.textPrimary, + ), keyboardType: TextInputType.url, decoration: InputDecoration( labelText: 'API endpoint', - labelStyle: TextStyle(color: Colors.white.withValues(alpha: 0.7)), + labelStyle: const TextStyle( + color: AppColors.textSecondary, + ), filled: true, - fillColor: Colors.white.withValues(alpha: 0.05), + fillColor: AppColors.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: const BorderSide(color: Colors.amber, width: 1.2), + borderSide: const BorderSide( + color: AppColors.accent, + width: 1.2, + ), ), ), ), @@ -573,39 +600,56 @@ class _SettingsScreenState extends State { obscureText: !_encryptionKeyVisible, enableSuggestions: false, autocorrect: false, - style: const TextStyle(color: Colors.white), + style: const TextStyle(color: AppColors.textPrimary), decoration: InputDecoration( - labelText: _encryptionKeyVisible ? 'Clave de cifrado' : 'Oculta hasta pulsar mostrar', - labelStyle: TextStyle(color: Colors.white.withValues(alpha: 0.7)), + labelText: _encryptionKeyVisible + ? 'Clave de cifrado' + : 'Oculta hasta pulsar mostrar', + labelStyle: const TextStyle( + color: AppColors.textSecondary, + ), filled: true, - fillColor: Colors.white.withValues(alpha: 0.05), + fillColor: AppColors.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: const BorderSide(color: Colors.amber, width: 1.2), + borderSide: const BorderSide( + color: AppColors.accent, + width: 1.2, + ), ), ), ), actions: [ ElevatedButton( - onPressed: _encryptionKeyLoading ? null : _loadEncryptionKey, + onPressed: _encryptionKeyLoading + ? null + : _loadEncryptionKey, child: _encryptionKeyLoading ? const SizedBox( width: 16, height: 16, - child: CircularProgressIndicator(strokeWidth: 2), + child: CircularProgressIndicator( + strokeWidth: 2, + ), ) : const Text('Mostrar'), ), OutlinedButton( - onPressed: _encryptionKeyVisible ? _hideEncryptionKey : null, + onPressed: _encryptionKeyVisible + ? _hideEncryptionKey + : null, child: const Text('Ocultar'), ), ], diff --git a/lib/screens/vault_access_screen.dart b/lib/screens/vault_access_screen.dart index 158b5e2..16d8ae7 100644 --- a/lib/screens/vault_access_screen.dart +++ b/lib/screens/vault_access_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:notas/data/api_client.dart'; +import 'package:notas/theme/app_colors.dart'; class VaultAccessScreen extends StatefulWidget { const VaultAccessScreen({ @@ -11,7 +12,8 @@ class VaultAccessScreen extends StatefulWidget { }); final bool isBusy; - final Future Function(String email, String password) onCreateAccountPressed; + final Future Function(String email, String password) + onCreateAccountPressed; final Future Function(String email, String password) onSignInPressed; final Future Function() onContinueWithoutAccount; @@ -75,17 +77,7 @@ class _VaultAccessScreenState extends State { Widget build(BuildContext context) { return Scaffold( body: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF191A1D), - Color(0xFF222326), - Color(0xFF101114), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), + decoration: const BoxDecoration(gradient: AppColors.backdropGradient), child: SafeArea( child: Column( children: [ @@ -98,12 +90,12 @@ class _VaultAccessScreenState extends State { child: Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( - color: const Color(0xFF1D1E20), + color: AppColors.surface, borderRadius: BorderRadius.circular(24), - border: Border.all(color: Colors.white.withValues(alpha: 0.08)), + border: Border.all(color: AppColors.borderMuted), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: 0.35), + color: AppColors.shadow, blurRadius: 30, offset: const Offset(0, 18), ), @@ -115,7 +107,7 @@ class _VaultAccessScreenState extends State { children: [ const Icon( Icons.lock_outline, - color: Colors.amber, + color: AppColors.accent, size: 44, ), const SizedBox(height: 16), @@ -123,7 +115,7 @@ class _VaultAccessScreenState extends State { 'Mis Notas', textAlign: TextAlign.center, style: TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 30, fontWeight: FontWeight.w700, ), @@ -133,7 +125,7 @@ class _VaultAccessScreenState extends State { 'Tus notas se guardan cifradas en este dispositivo. La cuenta y la sincronización vendrán después.', textAlign: TextAlign.center, style: TextStyle( - color: Colors.white.withValues(alpha: 0.72), + color: AppColors.textSecondary, height: 1.4, ), ), @@ -141,29 +133,42 @@ class _VaultAccessScreenState extends State { _endpointLoading ? const SizedBox( height: 48, - child: Center(child: CircularProgressIndicator()), + child: Center( + child: CircularProgressIndicator(), + ), ) : TextField( controller: _endpointController, enabled: !widget.isBusy, keyboardType: TextInputType.url, - style: const TextStyle(color: Colors.white), + style: const TextStyle( + color: AppColors.textPrimary, + ), decoration: InputDecoration( labelText: 'API endpoint', - labelStyle: TextStyle(color: Colors.white.withValues(alpha: 0.7)), + labelStyle: const TextStyle( + color: AppColors.textSecondary, + ), filled: true, - fillColor: Colors.white.withValues(alpha: 0.05), + fillColor: AppColors.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: const BorderSide(color: Colors.amber, width: 1.2), + borderSide: const BorderSide( + color: AppColors.accent, + width: 1.2, + ), ), ), ), @@ -172,23 +177,34 @@ class _VaultAccessScreenState extends State { controller: _emailController, enabled: !widget.isBusy, keyboardType: TextInputType.text, - style: const TextStyle(color: Colors.white), + style: const TextStyle( + color: AppColors.textPrimary, + ), decoration: InputDecoration( labelText: 'Usuario', - labelStyle: TextStyle(color: Colors.white.withValues(alpha: 0.7)), + labelStyle: const TextStyle( + color: AppColors.textSecondary, + ), filled: true, - fillColor: Colors.white.withValues(alpha: 0.05), + fillColor: AppColors.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: const BorderSide(color: Colors.amber, width: 1.2), + borderSide: const BorderSide( + color: AppColors.accent, + width: 1.2, + ), ), ), ), @@ -197,37 +213,54 @@ class _VaultAccessScreenState extends State { controller: _passwordController, enabled: !widget.isBusy, obscureText: true, - style: const TextStyle(color: Colors.white), + style: const TextStyle( + color: AppColors.textPrimary, + ), decoration: InputDecoration( labelText: 'Contraseña', - labelStyle: TextStyle(color: Colors.white.withValues(alpha: 0.7)), + labelStyle: const TextStyle( + color: AppColors.textSecondary, + ), filled: true, - fillColor: Colors.white.withValues(alpha: 0.05), + fillColor: AppColors.fill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: BorderSide(color: Colors.white.withValues(alpha: 0.12)), + borderSide: const BorderSide( + color: AppColors.border, + ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), - borderSide: const BorderSide(color: Colors.amber, width: 1.2), + borderSide: const BorderSide( + color: AppColors.accent, + width: 1.2, + ), ), ), ), const SizedBox(height: 22), FilledButton( - onPressed: widget.isBusy ? null : _handleCreateAccount, + onPressed: widget.isBusy + ? null + : _handleCreateAccount, style: FilledButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), + padding: const EdgeInsets.symmetric( + vertical: 14, + ), ), child: widget.isBusy ? const SizedBox( width: 18, height: 18, - child: CircularProgressIndicator(strokeWidth: 2), + child: CircularProgressIndicator( + strokeWidth: 2, + ), ) : const Text('Crear cuenta'), ), @@ -235,15 +268,21 @@ class _VaultAccessScreenState extends State { OutlinedButton( onPressed: widget.isBusy ? null : _handleSignIn, style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), - side: const BorderSide(color: Colors.white24), - foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + vertical: 14, + ), + side: const BorderSide( + color: AppColors.textDisabled, + ), + foregroundColor: AppColors.textPrimary, ), child: const Text('Iniciar sesión'), ), const SizedBox(height: 18), TextButton( - onPressed: widget.isBusy ? null : widget.onContinueWithoutAccount, + onPressed: widget.isBusy + ? null + : widget.onContinueWithoutAccount, child: const Text('Entrar sin cuenta'), ), ], @@ -259,4 +298,4 @@ class _VaultAccessScreenState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/theme/app_colors.dart b/lib/theme/app_colors.dart new file mode 100644 index 0000000..d87e938 --- /dev/null +++ b/lib/theme/app_colors.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; + +class AppColors { + AppColors._(); + + static const Color defaultThemeSeedColor = Colors.amber; + + static const Color scaffoldBackground = Color.fromRGBO(31, 32, 33, 1); + static const Color backdropStart = Color(0xFF191A1D); + static const Color backdropMid = Color(0xFF222326); + static const Color backdropEnd = Color(0xFF101114); + static const LinearGradient backdropGradient = LinearGradient( + colors: [backdropStart, backdropMid, backdropEnd], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ); + + static const Color surface = Color(0xFF1D1E20); + static const Color surfaceElevated = Color(0xFF303134); + static const Color drawerBackground = Color.fromARGB(255, 30, 31, 35); + static const Color cardBackground = Color.fromRGBO(24, 25, 26, 1); + + static const Color overlay = Color.fromARGB(140, 0, 0, 0); + static const Color shadow = Color.fromRGBO(0, 0, 0, 0.35); + static const Color transparent = Colors.transparent; + + static const Color accent = Colors.amber; + static const Color destructive = Colors.red; + static const Color destructiveAccent = Colors.redAccent; + static const Color success = Colors.green; + static const Color textOnAccent = Colors.black; + static const Color textOnSurfaceDark = Colors.black87; + + static const Color textPrimary = Colors.white; + static const Color textSecondary = Colors.white70; + static const Color textMuted = Colors.white54; + static const Color textSubtle = Colors.white38; + static const Color textDisabled = Colors.white24; + static const Color textHint = Color.fromRGBO(255, 255, 255, 0.30); + + static const Color borderStrong = Color.fromRGBO(255, 255, 255, 0.20); + static const Color border = Color.fromRGBO(255, 255, 255, 0.12); + static const Color borderMuted = Color.fromRGBO(255, 255, 255, 0.08); + static const Color fill = Color.fromRGBO(255, 255, 255, 0.05); + static const Color hover = Color.fromRGBO(255, 255, 255, 0.10); + static const Color searchFocusBorder = Color.fromRGBO(255, 255, 255, 0.40); + static const Color shadowSoft = Color.fromRGBO(0, 0, 0, 0.25); + static const Color shadowDim = Color.fromARGB(54, 0, 0, 0); + + static const Color categoryFallback = Color(0xFFFFC107); + static const List categoryColors = [ + Colors.amber, + Colors.blue, + Colors.green, + Colors.purple, + Colors.red, + Colors.teal, + Colors.orange, + Colors.grey, + ]; + + static const List themeSeedColors = [ + Colors.amber, + Colors.blue, + Colors.teal, + Colors.green, + Colors.pink, + Colors.purple, + ]; + + static const Color dragTargetBorder = Color(0xFF42A5F5); + + static const Color syncPreparing = Color.fromARGB(255, 165, 165, 165); + static const Color syncEncrypting = Color.fromARGB(255, 109, 191, 255); + static const Color syncUploading = Color.fromARGB(255, 98, 190, 255); + static const Color syncWaiting = Color.fromARGB(255, 150, 150, 150); + static const Color syncDecrypting = Color.fromARGB(255, 154, 194, 112); +} diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart index b820eb4..d508daf 100644 --- a/lib/theme/app_theme.dart +++ b/lib/theme/app_theme.dart @@ -1,15 +1,17 @@ import 'package:flutter/material.dart'; +import 'package:notas/theme/app_colors.dart'; class AppTheme { static ThemeData theme({Color seedColor = Colors.amber}) { final Brightness foregroundBrightness = ThemeData.estimateBrightnessForColor(seedColor); - final Color foregroundColor = - foregroundBrightness == Brightness.dark ? Colors.white : Colors.black; + final Color foregroundColor = foregroundBrightness == Brightness.dark + ? AppColors.textPrimary + : AppColors.textOnAccent; return ThemeData( useMaterial3: true, - scaffoldBackgroundColor: const Color.fromRGBO(31, 32, 33, 1), + scaffoldBackgroundColor: AppColors.scaffoldBackground, colorScheme: ColorScheme.fromSeed( seedColor: seedColor, brightness: Brightness.dark, @@ -20,4 +22,4 @@ class AppTheme { ), ); } -} \ No newline at end of file +} diff --git a/lib/widgets/category_style.dart b/lib/widgets/category_style.dart index 1e3da9a..e19b2d2 100644 --- a/lib/widgets/category_style.dart +++ b/lib/widgets/category_style.dart @@ -1,18 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:notas/theme/app_colors.dart'; class CategoryStyle { CategoryStyle._(); - static const List colors = [ - Colors.amber, - Colors.blue, - Colors.green, - Colors.purple, - Colors.red, - Colors.teal, - Colors.orange, - Colors.grey, - ]; + static const List colors = AppColors.categoryColors; static const List icons = [ Icons.label_outline_rounded, @@ -38,4 +30,4 @@ class CategoryStyle { return Icons.folder_outlined; } -} \ No newline at end of file +} diff --git a/lib/widgets/menu_drawer.dart b/lib/widgets/menu_drawer.dart index 8038279..2cbde66 100644 --- a/lib/widgets/menu_drawer.dart +++ b/lib/widgets/menu_drawer.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:notas/models/category.dart'; +import 'package:notas/theme/app_colors.dart'; import 'package:notas/widgets/category_style.dart'; class MenuDrawer extends StatelessWidget { @@ -22,10 +23,8 @@ class MenuDrawer extends StatelessWidget { Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( - color: Color.fromARGB(255, 30, 31, 35), - border: Border( - right: BorderSide(color: Colors.white12, width: 0.5), - ), + color: AppColors.drawerBackground, + border: Border(right: BorderSide(color: AppColors.border, width: 0.5)), ), child: Column( children: [ @@ -50,7 +49,7 @@ class MenuDrawer extends StatelessWidget { CategoryStyle.iconForCodePoint( category.iconCodePoint, ); - + return _MenuItemTile( icon: categoryIcon, label: category.name, @@ -59,8 +58,14 @@ class MenuDrawer extends StatelessWidget { onLongPress: onEditCategory == null ? null : () => onEditCategory?.call(category), - iconColor: Color(category.colorValue ?? 0xFFFFC107), - textColor: Color(category.colorValue ?? 0xFFFFC107), + iconColor: Color( + category.colorValue ?? + AppColors.categoryFallback.value, + ), + textColor: Color( + category.colorValue ?? + AppColors.categoryFallback.value, + ), trailing: IconButton( padding: const EdgeInsets.all(8), constraints: const BoxConstraints( @@ -69,7 +74,7 @@ class MenuDrawer extends StatelessWidget { ), icon: const Icon( Icons.more_vert, - color: Colors.white70, + color: AppColors.textSecondary, size: 20, ), onPressed: () => onEditCategory?.call(category), @@ -92,10 +97,10 @@ class MenuDrawer extends StatelessWidget { label: 'Mis notas borradas', selected: selectedItem == 'deleted_notes', onTap: () => onMenuItemTapped?.call('deleted_notes'), - iconColor: Colors.redAccent, - textColor: Colors.redAccent, + iconColor: AppColors.destructiveAccent, + textColor: AppColors.destructiveAccent, ), - const Divider(color: Colors.white12, height: 16), + const Divider(color: AppColors.border, height: 16), _MenuItemTile( icon: Icons.settings, label: 'Configuración', @@ -140,9 +145,11 @@ class _MenuItemTileState extends State<_MenuItemTile> { Widget build(BuildContext context) { final bool active = widget.selected || _hovering; final Color backgroundColor = active - ? Colors.white.withValues(alpha: 0.10) - : Colors.transparent; - final Color foregroundColor = active ? Colors.white : Colors.white70; + ? AppColors.hover + : AppColors.transparent; + final Color foregroundColor = active + ? AppColors.textPrimary + : AppColors.textSecondary; final Widget? trailing = _hovering ? widget.trailing : null; return MouseRegion( @@ -155,11 +162,7 @@ class _MenuItemTileState extends State<_MenuItemTile> { child: AnimatedContainer( duration: const Duration(milliseconds: 180), curve: Curves.easeOutCubic, - margin: const EdgeInsets.only( - right: 8, - top: 2, - bottom: 2, - ), + margin: const EdgeInsets.only(right: 8, top: 2, bottom: 2), child: Material( color: backgroundColor, borderRadius: const BorderRadius.only( @@ -169,11 +172,17 @@ class _MenuItemTileState extends State<_MenuItemTile> { clipBehavior: Clip.antiAlias, child: ListTile( contentPadding: const EdgeInsets.only(left: 16, right: 8), - leading: Icon(widget.icon, color: widget.iconColor ?? foregroundColor), + leading: Icon( + widget.icon, + color: widget.iconColor ?? foregroundColor, + ), trailing: trailing, title: Text( widget.label, - style: TextStyle(color: widget.textColor ?? foregroundColor, fontSize: 14), + style: TextStyle( + color: widget.textColor ?? foregroundColor, + fontSize: 14, + ), ), onTap: widget.onTap, onLongPress: widget.onLongPress, diff --git a/lib/widgets/note_card.dart b/lib/widgets/note_card.dart index fc03d47..dcf3269 100644 --- a/lib/widgets/note_card.dart +++ b/lib/widgets/note_card.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:notas/models/note.dart'; +import 'package:notas/theme/app_colors.dart'; // Small presentational widget for a note inside the grid. // Keep this widget lightweight and layout-agnostic: it should not force @@ -33,7 +34,9 @@ class _NoteCardState extends State { final bool showGrabbing = widget.isDragging || _isPressed; return MouseRegion( - cursor: showGrabbing ? SystemMouseCursors.grabbing : SystemMouseCursors.grab, + cursor: showGrabbing + ? SystemMouseCursors.grabbing + : SystemMouseCursors.grab, child: GestureDetector( onTapDown: widget.onTap == null ? null @@ -60,10 +63,10 @@ class _NoteCardState extends State { child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: const Color.fromRGBO(24, 25, 26, 1), + color: AppColors.cardBackground, borderRadius: BorderRadius.circular(12), border: Border.all( - color: widget.borderColor ?? Colors.white24, + color: widget.borderColor ?? AppColors.textDisabled, width: 1, ), ), @@ -87,7 +90,10 @@ class _NoteCardState extends State { final TextPainter textPainter = TextPainter( text: TextSpan( text: widget.note.body, - style: const TextStyle(color: Colors.white70, fontSize: 14), + style: const TextStyle( + color: AppColors.textSecondary, + fontSize: 14, + ), ), maxLines: 20, textDirection: TextDirection.ltr, @@ -105,7 +111,7 @@ class _NoteCardState extends State { Text( widget.note.title, style: const TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -115,7 +121,10 @@ class _NoteCardState extends State { const SizedBox(height: 8), Text( widget.note.body, - style: const TextStyle(color: Colors.white70, fontSize: 14), + style: const TextStyle( + color: AppColors.textSecondary, + fontSize: 14, + ), maxLines: 20, overflow: TextOverflow.clip, ), @@ -124,7 +133,7 @@ class _NoteCardState extends State { const Text( '...', style: TextStyle( - color: Colors.white54, + color: AppColors.textMuted, fontSize: 18, height: 1, ), @@ -138,4 +147,4 @@ class _NoteCardState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/widgets/search_app_bar.dart b/lib/widgets/search_app_bar.dart index e560f12..e5bd6d6 100644 --- a/lib/widgets/search_app_bar.dart +++ b/lib/widgets/search_app_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:notas/theme/app_colors.dart'; class SearchAppBar extends StatefulWidget { const SearchAppBar({ @@ -53,20 +54,19 @@ class _SearchAppBarState extends State { Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - color: Colors.transparent, - border: Border( - bottom: BorderSide( - color: Colors.white.withValues(alpha: 0.12), - width: 0.5, - ), - ), + color: AppColors.transparent, + border: Border(bottom: BorderSide(color: AppColors.border, width: 0.5)), ), padding: const EdgeInsets.only(left: 8, right: 20, top: 7, bottom: 7), child: Row( children: [ IconButton( onPressed: widget.onLeadingPressed ?? widget.onMenuPressed, - icon: Icon(widget.leadingIcon, color: Colors.white70, size: 20), + icon: Icon( + widget.leadingIcon, + color: AppColors.textSecondary, + size: 20, + ), tooltip: widget.leadingTooltip, splashRadius: 18, constraints: const BoxConstraints(minWidth: 40, minHeight: 40), @@ -84,18 +84,23 @@ class _SearchAppBarState extends State { child: TextField( controller: _searchController, onChanged: widget.onSearchChanged, - style: const TextStyle(color: Colors.white, fontSize: 13), - cursorColor: Colors.white70, + style: const TextStyle( + color: AppColors.textPrimary, + fontSize: 13, + ), + cursorColor: AppColors.textSecondary, decoration: InputDecoration( hintText: widget.searchHint, hintStyle: TextStyle( - color: Colors.white.withValues(alpha: 0.5), + color: AppColors.textSecondary.withValues( + alpha: 0.5, + ), ), suffixIcon: _searchController.text.isNotEmpty ? IconButton( icon: const Icon( Icons.clear, - color: Colors.white70, + color: AppColors.textSecondary, size: 18, ), onPressed: () { @@ -111,33 +116,33 @@ class _SearchAppBarState extends State { padding: EdgeInsets.only(right: 8), child: Icon( Icons.search, - color: Colors.white70, + color: AppColors.textSecondary, size: 18, ), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( - color: Colors.white.withValues(alpha: 0.2), + color: AppColors.borderStrong, width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( - color: Colors.white.withValues(alpha: 0.2), + color: AppColors.borderStrong, width: 0.5, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( - color: Colors.white.withValues(alpha: 0.4), + color: AppColors.searchFocusBorder, width: 0.5, ), ), filled: true, - fillColor: Colors.white.withValues(alpha: 0.05), + fillColor: AppColors.fill, contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8, @@ -152,7 +157,7 @@ class _SearchAppBarState extends State { child: Text( widget.titleText ?? '', style: const TextStyle( - color: Colors.white, + color: AppColors.textPrimary, fontSize: 18, fontWeight: FontWeight.w600, ), diff --git a/lib/widgets/sync_status_indicator.dart b/lib/widgets/sync_status_indicator.dart index 1b3eaa9..dd6e8ad 100644 --- a/lib/widgets/sync_status_indicator.dart +++ b/lib/widgets/sync_status_indicator.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:notas/theme/app_colors.dart'; import 'package:notas/widgets/sync_status.dart'; class SyncStatusIndicator extends StatelessWidget { @@ -91,7 +92,11 @@ class SyncStatusIndicator extends StatelessWidget { return Tooltip( message: _messageForStatus(), child: _buildIndicator( - const Icon(Icons.cloud_outlined, size: 16, color: Colors.white38), + const Icon( + Icons.cloud_outlined, + size: 16, + color: AppColors.textSubtle, + ), ), ); @@ -101,7 +106,7 @@ class SyncStatusIndicator extends StatelessWidget { child: _buildIndicator( _buildStatusBadge( icon: Icons.sync, - color: const Color.fromARGB(255, 165, 165, 165), + color: AppColors.syncPreparing, determinate: false, ), ), @@ -113,7 +118,7 @@ class SyncStatusIndicator extends StatelessWidget { child: _buildIndicator( _buildStatusBadge( icon: Icons.cloud_upload_outlined, - color: const Color.fromARGB(255, 109, 191, 255), + color: AppColors.syncEncrypting, determinate: true, ), ), @@ -125,7 +130,7 @@ class SyncStatusIndicator extends StatelessWidget { child: _buildIndicator( _buildStatusBadge( icon: Icons.cloud_upload, - color: const Color.fromARGB(255, 98, 190, 255), + color: AppColors.syncUploading, determinate: false, ), ), @@ -137,7 +142,7 @@ class SyncStatusIndicator extends StatelessWidget { child: _buildIndicator( _buildStatusBadge( icon: Icons.cloud_sync_outlined, - color: const Color.fromARGB(255, 150, 150, 150), + color: AppColors.syncWaiting, determinate: false, ), ), @@ -149,7 +154,7 @@ class SyncStatusIndicator extends StatelessWidget { child: _buildIndicator( _buildStatusBadge( icon: Icons.cloud_download_outlined, - color: const Color.fromARGB(255, 154, 194, 112), + color: AppColors.syncDecrypting, determinate: true, ), ), @@ -161,7 +166,7 @@ class SyncStatusIndicator extends StatelessWidget { child: _buildIndicator( _buildStatusBadge( icon: Icons.sync, - color: const Color.fromARGB(255, 150, 150, 150), + color: AppColors.syncWaiting, determinate: false, ), ), @@ -171,7 +176,7 @@ class SyncStatusIndicator extends StatelessWidget { return Tooltip( message: _messageForStatus(), child: _buildIndicator( - const Icon(Icons.check_circle, size: 16, color: Colors.green), + const Icon(Icons.check_circle, size: 16, color: AppColors.success), ), ); @@ -179,7 +184,7 @@ class SyncStatusIndicator extends StatelessWidget { return Tooltip( message: _messageForStatus(), child: _buildIndicator( - const Icon(Icons.error, size: 16, color: Colors.red), + const Icon(Icons.error, size: 16, color: AppColors.destructive), ), ); }