import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import '../modelos/gamificacion_usuario.dart'; import 'tema_app.dart'; class FondoFarolero extends StatelessWidget { final Widget child; final bool intenso; const FondoFarolero({ super.key, required this.child, this.intenso = false, }); @override Widget build(BuildContext context) { return DecoratedBox( decoration: const BoxDecoration(gradient: TemaApp.gradienteFondo), child: Stack( children: [ Positioned.fill( child: IgnorePointer( child: Image.asset( 'assets/ui/generated/shared/screen_atmosphere_bg.webp', fit: BoxFit.cover, opacity: AlwaysStoppedAnimation(intenso ? 0.76 : 0.48), filterQuality: FilterQuality.high, errorBuilder: (context, error, stackTrace) => const SizedBox.shrink(), ), ), ), Positioned.fill(child: child), ], ), ); } } class PanelFarolero extends StatelessWidget { final Widget child; final EdgeInsetsGeometry padding; final EdgeInsetsGeometry? margin; final Color? color; final Color? borderColor; const PanelFarolero({ super.key, required this.child, this.padding = const EdgeInsets.all(16), this.margin, this.color, this.borderColor, }); @override Widget build(BuildContext context) { return Container( width: double.infinity, margin: margin, decoration: TemaApp.decoracionPanel(color: color, borderColor: borderColor), child: ClipRRect( borderRadius: BorderRadius.circular(14), child: Stack( children: [ Padding(padding: padding, child: child), ], ), ), ); } } class EncabezadoFarolero extends StatelessWidget { final IconData icono; final String titulo; final String? subtitulo; final Color color; final Widget? trailing; final EdgeInsetsGeometry padding; const EncabezadoFarolero({ super.key, required this.icono, required this.titulo, this.subtitulo, this.color = TemaApp.colorNaranja, this.trailing, this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 18), }); @override Widget build(BuildContext context) { return PanelFarolero( padding: padding, child: Row( children: [ Container( width: 52, height: 52, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ color.withValues(alpha: 0.34), TemaApp.colorSuperficie.withValues(alpha: 0.72), ], ), border: Border.all(color: color.withValues(alpha: 0.72)), boxShadow: [ BoxShadow( color: color.withValues(alpha: 0.22), blurRadius: 22, ), ], ), child: Icon(icono, color: color, size: 30), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( titulo, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.headlineMedium?.copyWith( color: TemaApp.colorDorado, fontWeight: FontWeight.w900, ), ), if (subtitulo != null) ...[ const SizedBox(height: 3), Text( subtitulo!, maxLines: 2, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodyMedium, ), ], ], ), ), if (trailing != null) ...[ const SizedBox(width: 12), trailing!, ], ], ), ); } } class EstadoVacioFarolero extends StatelessWidget { final IconData icono; final String titulo; final String subtitulo; const EstadoVacioFarolero({ super.key, required this.icono, required this.titulo, required this.subtitulo, }); @override Widget build(BuildContext context) { return PanelFarolero( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 28), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(icono, color: TemaApp.colorNaranja, size: 46), const SizedBox(height: 14), Text( titulo, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( subtitulo, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), ], ), ); } } class LogoFarolero extends StatelessWidget { final double size; const LogoFarolero({super.key, this.size = 64}); @override Widget build(BuildContext context) { return Stack( alignment: Alignment.center, children: [ Positioned( top: 0, child: Icon( Icons.lightbulb, color: TemaApp.colorDorado.withValues(alpha: 0.32), size: size * 0.82, ), ), Text( 'FAROLERO', style: GoogleFonts.bangers( fontSize: size, color: TemaApp.colorNaranja, letterSpacing: 0, shadows: const [ Shadow(offset: Offset(3, 4), blurRadius: 0, color: Color(0xFF5E1205)), Shadow(offset: Offset(0, 0), blurRadius: 16, color: Color(0xFFFFC247)), ], ), ), ], ); } } class BotonFarolero extends StatelessWidget { final String texto; final IconData icono; final VoidCallback? onPressed; final LinearGradient gradient; final Color foreground; final bool destacado; const BotonFarolero({ super.key, required this.texto, required this.icono, required this.onPressed, this.gradient = TemaApp.gradientePrimario, this.foreground = Colors.black, this.destacado = true, }); const BotonFarolero.secundario({ super.key, required this.texto, required this.icono, required this.onPressed, }) : gradient = const LinearGradient( colors: [TemaApp.colorPurpura, Color(0xFF2B1736)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), foreground = Colors.white, destacado = false; const BotonFarolero.oscuro({ super.key, required this.texto, required this.icono, required this.onPressed, }) : gradient = const LinearGradient( colors: [Color(0xFF151F27), Color(0xFF090E13)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), foreground = TemaApp.colorTexto, destacado = false; @override Widget build(BuildContext context) { final habilitado = onPressed != null; final colorTexto = habilitado ? foreground : TemaApp.colorTextoSecundario; return Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(24), onTap: onPressed, child: ConstrainedBox( constraints: const BoxConstraints(minHeight: 66), child: CustomPaint( painter: MarcoBotonFaroleroPainter( gradient: habilitado ? gradient : const LinearGradient( colors: [TemaApp.colorTarjeta, TemaApp.colorSuperficie], ), destacado: destacado, habilitado: habilitado, ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 22, vertical: 15), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( width: 44, child: Icon(icono, color: colorTexto, size: 30), ), const SizedBox(width: 10), Expanded( child: Center( child: FittedBox( fit: BoxFit.scaleDown, child: Text( texto.toUpperCase(), maxLines: 1, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleMedium?.copyWith( color: colorTexto, fontSize: 19, fontWeight: FontWeight.w900, letterSpacing: 0.9, ), ), ), ), ), const SizedBox(width: 54), ], ), ), ), ), ), ); } } class TarjetaFaseFarolero extends StatelessWidget { final IconData icono; final String titulo; final String? subtitulo; final Color color; final Widget child; final EdgeInsetsGeometry padding; const TarjetaFaseFarolero({ super.key, required this.icono, required this.titulo, this.subtitulo, this.color = TemaApp.colorNaranja, this.child = const SizedBox.shrink(), this.padding = const EdgeInsets.all(18), }); @override Widget build(BuildContext context) { return PanelFarolero( padding: padding, borderColor: color.withValues(alpha: 0.48), color: TemaApp.colorSuperficie.withValues(alpha: 0.84), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 54, height: 54, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ color.withValues(alpha: 0.42), Colors.black.withValues(alpha: 0.62), ], ), border: Border.all(color: color.withValues(alpha: 0.72)), ), child: Icon(icono, color: color, size: 30), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( titulo, style: Theme.of(context).textTheme.titleLarge?.copyWith( color: TemaApp.colorDorado, fontWeight: FontWeight.w900, ), ), if (subtitulo != null) ...[ const SizedBox(height: 3), Text( subtitulo!, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: TemaApp.colorTextoSecundario, ), ), ], ], ), ), ], ), const SizedBox(height: 16), child, ], ), ); } } class EstadoJugadorFarolero extends StatelessWidget { final String nombre; final bool destacado; final bool completado; final IconData icono; final String? subtitulo; final VoidCallback? onTap; const EstadoJugadorFarolero({ super.key, required this.nombre, this.destacado = false, this.completado = false, this.icono = Icons.person, this.subtitulo, this.onTap, }); @override Widget build(BuildContext context) { final color = completado ? TemaApp.colorVerde : TemaApp.colorNaranja; return Padding( padding: const EdgeInsets.only(bottom: 10), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(18), onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( color: completado ? TemaApp.colorVerde.withValues(alpha: 0.14) : TemaApp.colorTarjeta.withValues(alpha: 0.84), borderRadius: BorderRadius.circular(18), border: Border.all( color: destacado ? TemaApp.colorDorado.withValues(alpha: 0.72) : color.withValues(alpha: completado ? 0.54 : 0.28), ), ), child: Row( children: [ Container( width: 42, height: 42, decoration: BoxDecoration( shape: BoxShape.circle, color: color.withValues(alpha: 0.16), border: Border.all(color: color.withValues(alpha: 0.72)), ), child: Icon(icono, color: color, size: 24), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( nombre, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: destacado ? FontWeight.w900 : FontWeight.w700, ), ), if (subtitulo != null) ...[ const SizedBox(height: 2), Text( subtitulo!, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: TemaApp.colorTextoSecundario, ), ), ], ], ), ), Icon( completado ? Icons.check_circle : Icons.hourglass_bottom, color: completado ? TemaApp.colorVerde : TemaApp.colorTextoSecundario, ), ], ), ), ), ), ); } } class SelectorVotoFarolero extends StatelessWidget { final String nombre; final bool seleccionado; final VoidCallback onTap; const SelectorVotoFarolero({ super.key, required this.nombre, required this.seleccionado, required this.onTap, }); @override Widget build(BuildContext context) { return EstadoJugadorFarolero( nombre: nombre, destacado: seleccionado, completado: seleccionado, icono: seleccionado ? Icons.check : Icons.person_search, onTap: onTap, ); } } class TemporizadorFarolero extends StatelessWidget { final String etiqueta; final String tiempo; final bool agotado; const TemporizadorFarolero({ super.key, required this.etiqueta, required this.tiempo, this.agotado = false, }); @override Widget build(BuildContext context) { final color = agotado ? TemaApp.colorAcento : TemaApp.colorNaranja; return PanelFarolero( padding: const EdgeInsets.all(22), borderColor: color.withValues(alpha: 0.62), color: color.withValues(alpha: agotado ? 0.18 : 0.10), child: Stack( alignment: Alignment.center, children: [ Image.asset( 'assets/ui/generated/gameplay/gameplay_phase_emblem.webp', height: 132, fit: BoxFit.contain, opacity: const AlwaysStoppedAnimation(0.34), ), Column( mainAxisSize: MainAxisSize.min, children: [ Text( etiqueta, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), Text( tiempo, style: Theme.of(context).textTheme.displaySmall?.copyWith( color: color, fontWeight: FontWeight.w900, ), ), ], ), ], ), ); } } class MarcoBotonFaroleroPainter extends CustomPainter { final LinearGradient gradient; final bool destacado; final bool habilitado; final double radio; const MarcoBotonFaroleroPainter({ required this.gradient, required this.destacado, required this.habilitado, this.radio = 24, }); @override void paint(Canvas canvas, Size size) { final rect = Offset.zero & size; final cuerpo = rect.deflate(3); final rrect = RRect.fromRectAndRadius(cuerpo, Radius.circular(radio)); final alpha = habilitado ? 1.0 : 0.42; final oro = TemaApp.colorDorado.withValues(alpha: 0.95 * alpha); final brillo = TemaApp.colorNaranja.withValues(alpha: 0.80 * alpha); final sombra = Paint() ..color = Colors.black.withValues(alpha: 0.38) ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 12); canvas.drawRRect(rrect.shift(const Offset(0, 8)), sombra); final base = Paint()..shader = gradient.createShader(cuerpo); canvas.drawRRect(rrect, base); final vignette = Paint() ..shader = LinearGradient( colors: [ Colors.white.withValues(alpha: destacado ? 0.34 : 0.08), Colors.transparent, Colors.black.withValues(alpha: destacado ? 0.10 : 0.34), ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ).createShader(cuerpo); canvas.drawRRect(rrect, vignette); final bordeExterior = Paint() ..style = PaintingStyle.stroke ..strokeWidth = destacado ? 2.4 : 1.8 ..shader = LinearGradient( colors: [oro, Colors.white.withValues(alpha: 0.72 * alpha), brillo, oro], ).createShader(cuerpo); canvas.drawRRect(rrect, bordeExterior); final bordeInterior = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 1.1 ..color = Colors.white.withValues(alpha: destacado ? 0.38 * alpha : 0.16 * alpha); canvas.drawRRect( RRect.fromRectAndRadius(cuerpo.deflate(6), Radius.circular(math.max(8, radio - 7))), bordeInterior, ); final railPaint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 1.5 ..color = oro.withValues(alpha: destacado ? 0.48 * alpha : 0.34 * alpha); final yTop = cuerpo.top + size.height * 0.25; final yBottom = cuerpo.bottom - size.height * 0.25; canvas.drawLine(Offset(cuerpo.left + 54, yTop), Offset(cuerpo.right - 54, yTop), railPaint); canvas.drawLine( Offset(cuerpo.left + 54, yBottom), Offset(cuerpo.right - 54, yBottom), railPaint, ); _drawSideOrnament(canvas, cuerpo, true, oro, brillo, alpha); _drawSideOrnament(canvas, cuerpo, false, oro, brillo, alpha); _drawCenterJewel(canvas, cuerpo.topCenter, 1, oro, brillo, alpha); _drawCenterJewel(canvas, cuerpo.bottomCenter, -1, oro, brillo, alpha); } void _drawSideOrnament( Canvas canvas, Rect rect, bool left, Color oro, Color brillo, double alpha, ) { final cx = left ? rect.left + 24 : rect.right - 24; final cy = rect.center.dy; final dir = left ? -1.0 : 1.0; final path = Path() ..moveTo(cx, cy - 18) ..lineTo(cx + dir * 24, cy) ..lineTo(cx, cy + 18) ..lineTo(cx - dir * 7, cy) ..close(); final paint = Paint() ..shader = LinearGradient( colors: [oro, brillo, Colors.white.withValues(alpha: 0.70 * alpha)], ).createShader(path.getBounds()); canvas.drawPath(path, paint); canvas.drawPath( path, Paint() ..style = PaintingStyle.stroke ..strokeWidth = 1 ..color = Colors.white.withValues(alpha: 0.42 * alpha), ); } void _drawCenterJewel( Canvas canvas, Offset anchor, double direction, Color oro, Color brillo, double alpha, ) { final cy = anchor.dy + direction * 3; final path = Path() ..moveTo(anchor.dx, cy - direction * 9) ..lineTo(anchor.dx + 12, cy) ..lineTo(anchor.dx, cy + direction * 9) ..lineTo(anchor.dx - 12, cy) ..close(); canvas.drawPath( path, Paint() ..shader = LinearGradient( colors: [Colors.white.withValues(alpha: 0.78 * alpha), oro, brillo], begin: Alignment.topCenter, end: Alignment.bottomCenter, ).createShader(path.getBounds()), ); } @override bool shouldRepaint(covariant MarcoBotonFaroleroPainter oldDelegate) { return oldDelegate.gradient != gradient || oldDelegate.destacado != destacado || oldDelegate.habilitado != habilitado || oldDelegate.radio != radio; } } class ArteGameplayFarolero extends StatelessWidget { final String assetPath; final double height; final double opacity; final EdgeInsetsGeometry padding; const ArteGameplayFarolero({ super.key, required this.assetPath, this.height = 128, this.opacity = 0.92, this.padding = EdgeInsets.zero, }); const ArteGameplayFarolero.fase({ super.key, this.height = 128, this.opacity = 0.92, this.padding = EdgeInsets.zero, }) : assetPath = 'assets/ui/generated/gameplay/gameplay_phase_emblem.webp'; const ArteGameplayFarolero.notas({ super.key, this.height = 150, this.opacity = 0.94, this.padding = EdgeInsets.zero, }) : assetPath = 'assets/ui/generated/gameplay/notes_strategy_art.webp'; const ArteGameplayFarolero.ajustes({ super.key, this.height = 150, this.opacity = 0.94, this.padding = EdgeInsets.zero, }) : assetPath = 'assets/ui/generated/meta/settings_profile_art.webp'; const ArteGameplayFarolero.historial({ super.key, this.height = 150, this.opacity = 0.94, this.padding = EdgeInsets.zero, }) : assetPath = 'assets/ui/generated/meta/history_ledger_art.webp'; const ArteGameplayFarolero.resultado({ super.key, this.height = 150, this.opacity = 0.94, this.padding = EdgeInsets.zero, }) : assetPath = 'assets/ui/generated/meta/result_verdict_art.webp'; @override Widget build(BuildContext context) { return ExcludeSemantics( child: Padding( padding: padding, child: SizedBox( height: height, width: double.infinity, child: Image.asset( assetPath, fit: BoxFit.contain, opacity: AlwaysStoppedAnimation(opacity), filterQuality: FilterQuality.high, errorBuilder: (context, error, stackTrace) => const SizedBox.shrink(), ), ), ), ); } } class AccesoFarolero extends StatelessWidget { final String etiqueta; final IconData icono; final VoidCallback onPressed; const AccesoFarolero({ super.key, required this.etiqueta, required this.icono, required this.onPressed, }); @override Widget build(BuildContext context) { return Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(8), onTap: onPressed, child: Ink( height: 66, decoration: TemaApp.decoracionPanel(color: TemaApp.colorSuperficie), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icono, color: TemaApp.colorNaranja, size: 22), const SizedBox(height: 5), Text( etiqueta.toUpperCase(), maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: TemaApp.colorDorado, fontSize: 11, fontWeight: FontWeight.w700, ), ), ], ), ), ), ); } } class TarjetaPalabraFarolero extends StatelessWidget { final String palabra; const TarjetaPalabraFarolero({super.key, required this.palabra}); @override Widget build(BuildContext context) { return Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 28), decoration: BoxDecoration( color: const Color(0xFFC48642), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFF6B3519), width: 2), boxShadow: [ BoxShadow( color: TemaApp.colorNaranja.withValues(alpha: 0.28), blurRadius: 24, ), ], ), child: Stack( alignment: Alignment.center, children: [ Positioned.fill( child: Image.asset( 'assets/ui/generated/gameplay/gameplay_phase_emblem.webp', fit: BoxFit.contain, opacity: const AlwaysStoppedAnimation(0.14), filterQuality: FilterQuality.high, errorBuilder: (context, error, stackTrace) => const SizedBox.shrink(), ), ), Text( palabra.toUpperCase(), textAlign: TextAlign.center, style: GoogleFonts.oswald( color: const Color(0xFF1B0C05), fontSize: 42, fontWeight: FontWeight.w900, letterSpacing: 0, ), ), ], ), ); } } class AvatarFarolero extends StatelessWidget { final String texto; final String? assetPath; final Color color; final double size; final int fuego; final List medallas; const AvatarFarolero({ super.key, required this.texto, this.assetPath, this.color = TemaApp.colorNaranja, this.size = 40, this.fuego = 0, this.medallas = const [], }); @override Widget build(BuildContext context) { final lienzo = size + 10; return SizedBox( width: lienzo, height: lienzo, child: Stack( clipBehavior: Clip.none, alignment: Alignment.center, children: [ CustomPaint( size: Size(lienzo, lienzo), painter: _FuegoAvatarPainter(fuego: fuego), ), Container( width: size, height: size, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [color.withValues(alpha: 0.9), TemaApp.colorSuperficie], ), border: Border.all(color: TemaApp.colorDorado, width: 2), ), child: Center( child: assetPath == null ? Text( texto, style: TextStyle( color: TemaApp.colorTexto, fontWeight: FontWeight.bold, fontSize: size * 0.36, ), ) : ClipOval( child: Image.asset( assetPath!, width: size, height: size, fit: BoxFit.contain, filterQuality: FilterQuality.high, ), ), ), ), if (medallas.isNotEmpty) Positioned( right: -2, bottom: -4, child: _MiniMedalla(id: medallas.first), ), ], ), ); } } class MedallasCompactasFarolero extends StatelessWidget { final List ids; final int max; const MedallasCompactasFarolero({ super.key, required this.ids, this.max = 3, }); @override Widget build(BuildContext context) { final visibles = ids.take(max).toList(); if (visibles.isEmpty) return const SizedBox.shrink(); return Wrap( spacing: 4, runSpacing: 4, children: [ for (final id in visibles) _MiniMedalla(id: id), ], ); } } class _MiniMedalla extends StatelessWidget { final String id; const _MiniMedalla({required this.id}); @override Widget build(BuildContext context) { final medalla = EstadisticasPerfilUsuario.catalogoMedallas[id]; if (medalla == null) return const SizedBox.shrink(); return Tooltip( message: '${medalla.nombre}: ${medalla.descripcion}', child: Container( width: 26, height: 26, alignment: Alignment.center, decoration: BoxDecoration( color: TemaApp.colorSuperficie.withValues(alpha: 0.92), shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.32), blurRadius: 6, offset: const Offset(0, 2), ), ], ), child: Image.asset( medalla.assetPath, width: 26, height: 26, fit: BoxFit.contain, errorBuilder: (context, error, stackTrace) => Text(medalla.emoji, style: const TextStyle(fontSize: 12)), ), ), ); } } class _FuegoAvatarPainter extends CustomPainter { final int fuego; const _FuegoAvatarPainter({required this.fuego}); @override void paint(Canvas canvas, Size size) { final porcentaje = fuego.clamp(0, 100) / 100; final rect = Offset.zero & size; final centro = rect.center; final radio = math.min(size.width, size.height) / 2 - 3; final base = Paint() ..isAntiAlias = true ..style = PaintingStyle.stroke ..strokeWidth = 4 ..strokeCap = StrokeCap.round ..color = Colors.black.withValues(alpha: 0.28); canvas.drawCircle(centro, radio, base); if (porcentaje <= 0) return; final fuegoPaint = Paint() ..isAntiAlias = true ..style = PaintingStyle.stroke ..strokeWidth = 4 ..strokeCap = StrokeCap.round ..shader = const SweepGradient( colors: [Color(0xFFFFC247), Color(0xFFFF7A1A), Color(0xFFE53935)], ).createShader(Rect.fromCircle(center: centro, radius: radio)); canvas.drawArc( Rect.fromCircle(center: centro, radius: radio), -math.pi / 2, math.pi * 2 * porcentaje, false, fuegoPaint, ); } @override bool shouldRepaint(covariant _FuegoAvatarPainter oldDelegate) { return oldDelegate.fuego != fuego; } }