import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; enum MascotMood { neutral, wave, celebrate, think, analyze } class Mascot extends StatelessWidget { final MascotMood mood; final double size; const Mascot({super.key, this.mood = MascotMood.neutral, this.size = 160}); @override Widget build(BuildContext context) { return SizedBox( width: size, height: size, child: Stack( alignment: Alignment.center, children: [ _mascotImage(), if (mood == MascotMood.celebrate) ..._sparkles(), if (mood == MascotMood.analyze) _magnifier(), if (mood == MascotMood.think) _thoughtBubble(), ], ), ); } Widget _mascotImage() { final img = Image.asset( 'assets/images/shaynee_hero.png', width: size, height: size, fit: BoxFit.contain, ); return switch (mood) { MascotMood.neutral => img .animate(onPlay: (c) => c.repeat(reverse: true)) .moveY(begin: 0, end: -8, duration: 1800.ms, curve: Curves.easeInOut), MascotMood.wave => img .animate(onPlay: (c) => c.repeat(reverse: true)) .moveY(begin: 0, end: -6, duration: 1600.ms, curve: Curves.easeInOut), MascotMood.celebrate => img .animate(onPlay: (c) => c.repeat(reverse: true)) .scaleXY(begin: 0.95, end: 1.05, duration: 700.ms, curve: Curves.easeInOut) .moveY(begin: 0, end: -10, duration: 700.ms, curve: Curves.easeInOut), MascotMood.think => img .animate(onPlay: (c) => c.repeat(reverse: true)) .moveX(begin: 0, end: 4, duration: 2000.ms, curve: Curves.easeInOut), MascotMood.analyze => img .animate(onPlay: (c) => c.repeat(reverse: true)) .moveY(begin: 0, end: -5, duration: 2000.ms, curve: Curves.easeInOut), }; } List _sparkles() { const positions = [ Offset(-50, -30), Offset(50, -40), Offset(-40, 30), Offset(55, 20), Offset(0, -55), ]; return positions.asMap().entries.map((e) { final i = e.key; final pos = e.value; return Positioned( left: size / 2 + pos.dx, top: size / 2 + pos.dy, child: _Sparkle(delay: i * 200), ); }).toList(); } Widget _magnifier() { return Positioned( right: 0, bottom: size * 0.15, child: Container( width: size * 0.35, height: size * 0.35, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: const Color(0xFF5B4FCF), width: 3), color: Colors.white.withAlpha(180), ), child: const Icon(Icons.search, color: Color(0xFF5B4FCF), size: 20), ) .animate(onPlay: (c) => c.repeat(reverse: true)) .rotate(begin: -0.05, end: 0.05, duration: 1500.ms), ); } Widget _thoughtBubble() { return Positioned( top: 0, right: 0, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFFE8E6F0), width: 1.5), boxShadow: [ BoxShadow(color: Colors.black.withAlpha(12), blurRadius: 8), ], ), child: const Text('🤔', style: TextStyle(fontSize: 18)), ) .animate() .fadeIn(duration: 500.ms) .scaleXY(begin: 0.5, end: 1.0, duration: 400.ms, curve: Curves.elasticOut), ); } } class _Sparkle extends StatelessWidget { final int delay; const _Sparkle({required this.delay}); @override Widget build(BuildContext context) { return const Text('✨', style: TextStyle(fontSize: 14)) .animate(onPlay: (c) => c.repeat(reverse: true), delay: Duration(milliseconds: delay)) .scaleXY(begin: 0.5, end: 1.2, duration: 800.ms, curve: Curves.easeInOut) .fadeIn(duration: 400.ms); } }