import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:lottie/lottie.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import '/core/auth_provider.dart'; import '/models/invite.dart'; import '/features/auth/invite_pending_screen.dart'; class SplashScreen extends ConsumerStatefulWidget { const SplashScreen({super.key}); @override ConsumerState createState() => _SplashScreenState(); } class _SplashScreenState extends ConsumerState with SingleTickerProviderStateMixin { late AnimationController _ctrl; @override void initState() { super.initState(); _ctrl = AnimationController(vsync: this, duration: const Duration(seconds: 2)); _ctrl.forward(); Future.delayed(const Duration(milliseconds: 2200), _navigate); } Future _navigate() async { if (!mounted) return; try { await ref.read(authNotifierProvider.future); final session = await ref.read(currentSessionProvider.future); if (!mounted) return; if (session == null) { context.go('/login'); return; } // ─── Verificar se o utilizador tem perfil final supabase = Supabase.instance.client; final profile = await supabase .from('profiles') .select() .eq('user_id', session.user.id) .maybeSingle(); // ─── Verificar convite pendente pelo email final email = session.user.email ?? ''; final inviteData = await supabase .from('invites') .select() .eq('email', email) .eq('status', 'pending') .gt('expires_at', DateTime.now().toIso8601String()) .order('created_at', ascending: false) .limit(1) .maybeSingle(); if (!mounted) return; if (inviteData != null) { final invite = Invite.fromMap(inviteData); if (!invite.isExpired) { // Mostrar ecrã de aceitação de convite Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => InvitePendingScreen(invite: invite)), ); return; } } if (profile == null) { // Sem perfil e sem convite → ecrã de espera / registo incompleto context.go('/login'); } else { context.go('/home'); } } catch (_) { if (mounted) context.go('/login'); } } @override void dispose() { _ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF0D1117), body: Stack(children: [ // Orbs Positioned(top: -100, right: -80, child: _orb(300, const Color(0xFF4FC3F7).withOpacity(0.08))), Positioned(bottom: -80, left: -60, child: _orb(250, const Color(0xFFA5D6A7).withOpacity(0.06))), SafeArea( child: Center( child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ // Logo com glow Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient(colors: [ const Color(0xFF4FC3F7).withOpacity(0.15), Colors.transparent, ]), border: Border.all(color: const Color(0xFF4FC3F7).withOpacity(0.2), width: 1.5), ), child: Image.asset('assets/logo.png', height: 100, errorBuilder: (_, __, ___) => const Icon(Icons.child_care, size: 80, color: Color(0xFF4FC3F7))), ), const SizedBox(height: 24), const Text('SEMENTES DO FUTURO', style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.w900, letterSpacing: 2)), const SizedBox(height: 6), const Text('Diário do Candengue', style: TextStyle(color: Color(0xFF4FC3F7), fontSize: 13, letterSpacing: 1.5)), const SizedBox(height: 48), Lottie.asset('assets/splash_animation.json', controller: _ctrl, height: 80, repeat: false, errorBuilder: (_, __, ___) => const SizedBox( height: 40, width: 40, child: CircularProgressIndicator(color: Color(0xFF4FC3F7), strokeWidth: 2), )), const SizedBox(height: 16), Text('"Conforto, cuidado e aprendizagem"', style: TextStyle(color: Colors.white.withOpacity(0.3), fontSize: 12, fontStyle: FontStyle.italic)), ]), ), ), ]), ); } Widget _orb(double size, Color color) => Container(width: size, height: size, decoration: BoxDecoration(shape: BoxShape.circle, color: color, boxShadow: [BoxShadow(color: color, blurRadius: size / 2)])); }