From 8aa03f437c5c99561061f03a8b5c646ffb6bf70d Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sat, 27 Jun 2026 08:48:55 -0500 Subject: [PATCH] fix: simplificar navbar, iconos siempre visibles - Quitar AnimatedSwitcher/RotationTransition que ocultaba los iconos - Icono sol/luna y campana con InkWell simple y colores explicitos - Fondo navbar animado segun tema (isDark) - DashboardLayout usa scaffoldBackgroundColor del tema Co-Authored-By: Claude Sonnet 4.6 --- .../layouts/dashboard/dashboard_layout.dart | 2 +- lib/ui/shared/navbar.dart | 319 +++++++++--------- 2 files changed, 160 insertions(+), 161 deletions(-) diff --git a/lib/ui/layouts/dashboard/dashboard_layout.dart b/lib/ui/layouts/dashboard/dashboard_layout.dart index 4a228b5..5d02db9 100644 --- a/lib/ui/layouts/dashboard/dashboard_layout.dart +++ b/lib/ui/layouts/dashboard/dashboard_layout.dart @@ -27,7 +27,7 @@ class _DashboardLayoutState extends State final size = MediaQuery.of(context).size; return Scaffold( - backgroundColor: const Color(0xffEDF1F2), + backgroundColor: Theme.of(context).scaffoldBackgroundColor, body: Stack( children: [ Row( diff --git a/lib/ui/shared/navbar.dart b/lib/ui/shared/navbar.dart index 3f6dc6c..c054c4a 100644 --- a/lib/ui/shared/navbar.dart +++ b/lib/ui/shared/navbar.dart @@ -14,160 +14,158 @@ class Navbar extends StatelessWidget { @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; - final professionalProvider = Provider.of(context); - final themeProvider = Provider.of(context); - final scoreProvider = Provider.of(context, listen: false); - final isDark = themeProvider.isDark; - WidgetsBinding.instance.addPostFrameCallback((_) { - scoreProvider.loadReputation(context.read().user!.id); - }); + return Consumer(builder: (context, themeProvider, _) { + final isDark = themeProvider.isDark; + final iconColor = isDark ? Colors.white70 : const Color(0xFF475569); + final bgColor = isDark ? const Color(0xFF1E293B) : Colors.white; + final shadowColor = isDark ? Colors.black54 : Colors.black12; - return Consumer(builder: (context, scoreProvider, _) { - final reputation = scoreProvider.reputation; + return Consumer(builder: (context, scoreProvider, _) { + final professionalProvider = + Provider.of(context, listen: false); - return AnimatedContainer( - duration: const Duration(milliseconds: 250), - width: double.infinity, - height: 56, - decoration: BoxDecoration( - color: isDark ? const Color(0xFF1E293B) : Colors.white, - boxShadow: [ - BoxShadow( - color: isDark ? Colors.black45 : Colors.black12, - blurRadius: 6, - ), - ], - ), - child: Row( - children: [ - if (size.width <= 700) - IconButton( - icon: Icon(Icons.menu_outlined, - color: isDark ? Colors.white70 : Colors.black54), - onPressed: () => SideMenuProvider.openMenu(), - ), - const SizedBox(width: 8), - const Spacer(), + WidgetsBinding.instance.addPostFrameCallback((_) { + scoreProvider.loadReputation( + context.read().user!.id); + }); - // Puntuación - Row( - children: [ - Icon(Icons.star, color: Colors.amber[600], size: 16), - const SizedBox(width: 3), - Text( - professionalProvider.isProModeActive - ? reputation.averagePro.toStringAsFixed(1) - : reputation.average.toStringAsFixed(1), - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: isDark ? Colors.white70 : Colors.black87, - ), + final reputation = scoreProvider.reputation; + + return Container( + width: double.infinity, + height: 56, + decoration: BoxDecoration( + color: bgColor, + boxShadow: [BoxShadow(color: shadowColor, blurRadius: 6)], + ), + child: Row( + children: [ + // Menú hamburguesa (móvil) + if (size.width <= 700) + IconButton( + icon: Icon(Icons.menu, color: iconColor), + onPressed: () => SideMenuProvider.openMenu(), ), - ], - ), - const SizedBox(width: 4), + const Spacer(), - // Toggle día / noche - Tooltip( - message: isDark ? 'Modo día' : 'Modo noche', - child: IconButton( - onPressed: themeProvider.toggle, - icon: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: (child, anim) => RotationTransition( - turns: anim, - child: FadeTransition(opacity: anim, child: child), - ), - child: Icon( - isDark ? Icons.light_mode_rounded : Icons.dark_mode_rounded, - key: ValueKey(isDark), - color: isDark ? Colors.amber : const Color(0xFF64748B), - size: 22, + // Puntuación + Icon(Icons.star_rounded, color: Colors.amber, size: 17), + const SizedBox(width: 3), + Text( + professionalProvider.isProModeActive + ? reputation.averagePro.toStringAsFixed(1) + : reputation.average.toStringAsFixed(1), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: isDark ? Colors.white70 : const Color(0xFF1E293B), + ), + ), + + const SizedBox(width: 8), + + // Toggle día / noche + Tooltip( + message: isDark ? 'Cambiar a modo día' : 'Cambiar a modo noche', + child: InkWell( + borderRadius: BorderRadius.circular(20), + onTap: themeProvider.toggle, + child: Padding( + padding: const EdgeInsets.all(8), + child: Icon( + isDark ? Icons.light_mode : Icons.dark_mode, + color: isDark ? Colors.amber : iconColor, + size: 22, + ), ), ), ), - ), - // Campana - _NotificationBell(isDark: isDark), + // Campana de notificaciones + _NotificationBell(isDark: isDark, iconColor: iconColor), - // Avatar - const NavbarAvatar(), - const SizedBox(width: 12), - ], - ), - ); + const SizedBox(width: 4), + + // Avatar + const NavbarAvatar(), + const SizedBox(width: 14), + ], + ), + ); + }); }); } } class _NotificationBell extends StatelessWidget { final bool isDark; - const _NotificationBell({required this.isDark}); + final Color iconColor; + const _NotificationBell({required this.isDark, required this.iconColor}); @override Widget build(BuildContext context) { - final professionalProvider = Provider.of(context); - return Consumer(builder: (context, sp, _) { - final pending = sp.services - .where((s) => s.service.status.index == 0) - .length; + final pendingCount = + sp.services.where((s) => s.service.status.index == 0).length; - return Stack( - clipBehavior: Clip.none, - children: [ - IconButton( - tooltip: 'Notificaciones', - icon: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: Icon( - pending > 0 - ? Icons.notifications_active_rounded - : Icons.notifications_outlined, - key: ValueKey(pending > 0), - color: pending > 0 - ? const Color(0xFF42A4EF) - : (isDark ? Colors.white54 : const Color(0xFF64748B)), - size: 22, + return Tooltip( + message: 'Notificaciones', + child: Stack( + clipBehavior: Clip.none, + children: [ + InkWell( + borderRadius: BorderRadius.circular(20), + onTap: () => _showSheet(context, sp), + child: Padding( + padding: const EdgeInsets.all(8), + child: Icon( + pendingCount > 0 + ? Icons.notifications_active + : Icons.notifications_outlined, + color: pendingCount > 0 + ? const Color(0xFF42A4EF) + : iconColor, + size: 22, + ), ), ), - onPressed: () => _showSheet(context, professionalProvider.isProModeActive, sp), - ), - if (pending > 0) - Positioned( - top: 6, - right: 6, - child: Container( - width: 16, - height: 16, - decoration: const BoxDecoration( - color: Color(0xFFEF4444), - shape: BoxShape.circle, - ), - child: Center( - child: Text( - pending > 9 ? '9+' : '$pending', - style: const TextStyle( - color: Colors.white, - fontSize: 9, - fontWeight: FontWeight.bold, + if (pendingCount > 0) + Positioned( + top: 4, + right: 4, + child: Container( + width: 15, + height: 15, + decoration: const BoxDecoration( + color: Color(0xFFEF4444), + shape: BoxShape.circle, + ), + child: Center( + child: Text( + pendingCount > 9 ? '9+' : '$pendingCount', + style: const TextStyle( + color: Colors.white, + fontSize: 8, + fontWeight: FontWeight.bold, + ), ), ), ), ), - ), - ], + ], + ), ); }); } - void _showSheet(BuildContext context, bool isPro, ServicesProvider sp) { + void _showSheet(BuildContext context, ServicesProvider sp) { final isDark = Theme.of(context).brightness == Brightness.dark; - final pending = sp.services.where((s) => s.service.status.index == 0).toList(); + final pending = + sp.services.where((s) => s.service.status.index == 0).toList(); + final isPro = Provider.of(context, listen: false) + .isProModeActive; showModalBottomSheet( context: context, @@ -183,7 +181,8 @@ class _NotificationBell extends StatelessWidget { children: [ Center( child: Container( - width: 36, height: 4, + width: 36, + height: 4, decoration: BoxDecoration( color: Colors.grey[400], borderRadius: BorderRadius.circular(2), @@ -193,25 +192,23 @@ class _NotificationBell extends StatelessWidget { const SizedBox(height: 16), Row( children: [ - Icon(Icons.notifications_outlined, - size: 20, color: isDark ? Colors.white70 : Colors.black87), + const Icon(Icons.notifications_outlined, size: 20), const SizedBox(width: 8), - Text('Notificaciones', + const Text('Notificaciones', style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: isDark ? Colors.white : Colors.black87, - )), + fontSize: 16, fontWeight: FontWeight.bold)), const Spacer(), if (pending.isNotEmpty) Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 3), decoration: BoxDecoration( color: const Color(0xFF42A4EF), borderRadius: BorderRadius.circular(10), ), child: Text('${pending.length} nuevas', - style: const TextStyle(color: Colors.white, fontSize: 11)), + style: const TextStyle( + color: Colors.white, fontSize: 11)), ), ], ), @@ -231,36 +228,38 @@ class _NotificationBell extends StatelessWidget { ) else ...pending.take(5).map((s) => ListTile( - contentPadding: EdgeInsets.zero, - leading: Container( - width: 40, height: 40, - decoration: BoxDecoration( - color: const Color(0xFF42A4EF).withOpacity(0.12), - shape: BoxShape.circle, - ), - child: const Icon(Icons.room_service_outlined, - color: Color(0xFF42A4EF), size: 20), - ), - title: Text( - isPro ? 'Nueva solicitud de servicio' : 'Servicio pendiente', - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w600, - color: isDark ? Colors.white : Colors.black87, - ), - ), - subtitle: Text( - s.service.address.isNotEmpty ? s.service.address : 'Sin dirección', - style: TextStyle( - fontSize: 12, - color: isDark ? Colors.white54 : Colors.black54, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - trailing: const Icon(Icons.circle, - color: Color(0xFF42A4EF), size: 8), - )), + contentPadding: EdgeInsets.zero, + leading: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: + const Color(0xFF42A4EF).withOpacity(0.12), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.room_service_outlined, + color: Color(0xFF42A4EF), + size: 20), + ), + title: Text( + isPro + ? 'Nueva solicitud de servicio' + : 'Servicio pendiente', + style: const TextStyle( + fontSize: 13, fontWeight: FontWeight.w600), + ), + subtitle: Text( + s.service.address.isNotEmpty + ? s.service.address + : 'Sin dirección', + style: const TextStyle(fontSize: 12), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + trailing: const Icon(Icons.circle, + color: Color(0xFF42A4EF), size: 8), + )), ], ), ),