import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:sizer/sizer.dart'; import '../../../core/app_export.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override State createState() => _SplashScreenState(); } class _SplashScreenState extends State with TickerProviderStateMixin { late AnimationController _logoAnimationController; late AnimationController _loadingAnimationController; late Animation _logoFadeAnimation; late Animation _logoScaleAnimation; late Animation _loadingOpacityAnimation; bool _showLoading = false; bool _initializationComplete = false; String _statusMessage = 'Iniciando SIBU...'; @override void initState() { super.initState(); _setupAnimations(); _startInitialization(); } void _setupAnimations() { // Logo animation controller _logoAnimationController = AnimationController( duration: const Duration(milliseconds: 1500), vsync: this, ); // Loading animation controller _loadingAnimationController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); // Logo fade in animation _logoFadeAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _logoAnimationController, curve: const Interval(0.0, 0.6, curve: Curves.easeOut), )); // Logo scale animation _logoScaleAnimation = Tween( begin: 0.8, end: 1.0, ).animate(CurvedAnimation( parent: _logoAnimationController, curve: const Interval(0.0, 0.8, curve: Curves.elasticOut), )); // Loading indicator opacity animation _loadingOpacityAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _loadingAnimationController, curve: Curves.easeIn, )); // Start logo animation _logoAnimationController.forward(); } Future _startInitialization() async { try { // Show loading indicator after logo animation await Future.delayed(const Duration(milliseconds: 1000)); setState(() { _showLoading = true; }); _loadingAnimationController.forward(); // Simulate initialization tasks await _performInitializationTasks(); // Mark initialization as complete setState(() { _initializationComplete = true; _statusMessage = 'Listo para usar'; }); // Navigate to main screen after brief delay await Future.delayed(const Duration(milliseconds: 500)); _navigateToMainScreen(); } catch (e) { _handleInitializationError(e); } } Future _performInitializationTasks() async { // Task 1: Check GPS permissions setState(() { _statusMessage = 'Verificando permisos GPS...'; }); await Future.delayed(const Duration(milliseconds: 600)); // Task 2: Load cached route data setState(() { _statusMessage = 'Cargando datos de rutas...'; }); await Future.delayed(const Duration(milliseconds: 700)); // Task 3: Fetch latest bus schedules setState(() { _statusMessage = 'Actualizando horarios...'; }); await Future.delayed(const Duration(milliseconds: 800)); // Task 4: Prepare map tiles setState(() { _statusMessage = 'Preparando mapas...'; }); await Future.delayed(const Duration(milliseconds: 500)); } void _navigateToMainScreen() { // Navigate to map screen (main tab) Navigator.pushReplacementNamed(context, '/map-screen'); } void _handleInitializationError(dynamic error) { setState(() { _statusMessage = 'Error de conexión'; }); // Show continue offline option after 5 seconds Future.delayed(const Duration(seconds: 5), () { if (mounted && !_initializationComplete) { _showContinueOfflineDialog(); } }); } void _showContinueOfflineDialog() { showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( backgroundColor: AppTheme.lightTheme.colorScheme.surface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), title: Text( 'Continuar sin conexión', style: AppTheme.lightTheme.textTheme.titleLarge?.copyWith( color: AppTheme.lightTheme.colorScheme.onSurface, ), ), content: Text( 'No se pudo conectar al servidor. ¿Deseas continuar con datos guardados?', style: AppTheme.lightTheme.textTheme.bodyMedium?.copyWith( color: AppTheme.lightTheme.colorScheme.onSurface, ), ), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); _startInitialization(); // Retry }, child: Text( 'Reintentar', style: TextStyle( color: AppTheme.lightTheme.colorScheme.primary, ), ), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _navigateToMainScreen(); }, style: ElevatedButton.styleFrom( backgroundColor: AppTheme.accentYellow, foregroundColor: AppTheme.primaryBlack, ), child: const Text('Continuar'), ), ], ); }, ); } Widget _buildLogo() { return AnimatedBuilder( animation: _logoAnimationController, builder: (context, child) { return Transform.scale( scale: _logoScaleAnimation.value, child: Opacity( opacity: _logoFadeAnimation.value, child: Container( width: 35.w, height: 35.w, decoration: BoxDecoration( color: AppTheme.accentYellow, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: AppTheme.primaryBlack.withValues(alpha: 0.2), blurRadius: 20, offset: const Offset(0, 8), ), ], ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CustomIconWidget( iconName: 'directions_bus', color: AppTheme.primaryBlack, size: 12.w, ), SizedBox(height: 1.h), Text( 'SIBU', style: AppTheme.lightTheme.textTheme.headlineSmall?.copyWith( color: AppTheme.primaryBlack, fontWeight: FontWeight.bold, letterSpacing: 2, ), ), ], ), ), ), ), ); }, ); } Widget _buildLoadingIndicator() { return _showLoading ? AnimatedBuilder( animation: _loadingAnimationController, builder: (context, child) { return Opacity( opacity: _loadingOpacityAnimation.value, child: Column( children: [ SizedBox(height: 8.h), SizedBox( width: 8.w, height: 8.w, child: CircularProgressIndicator( strokeWidth: 3, valueColor: AlwaysStoppedAnimation( AppTheme.accentYellow, ), backgroundColor: AppTheme.accentYellow.withValues(alpha: 0.3), ), ), SizedBox(height: 3.h), Text( _statusMessage, style: AppTheme.lightTheme.textTheme.bodyMedium?.copyWith( color: AppTheme.surfaceWhite.withValues(alpha: 0.8), ), textAlign: TextAlign.center, ), ], ), ); }, ) : const SizedBox.shrink(); } Widget _buildVersionInfo() { return Positioned( bottom: 8.h, left: 0, right: 0, child: Column( children: [ Text( 'Transporte Público Boquete', style: AppTheme.lightTheme.textTheme.bodySmall?.copyWith( color: AppTheme.surfaceWhite.withValues(alpha: 0.6), ), ), SizedBox(height: 1.h), Text( 'Versión 1.0.0', style: AppTheme.lightTheme.textTheme.labelSmall?.copyWith( color: AppTheme.surfaceWhite.withValues(alpha: 0.4), ), ), ], ), ); } @override void dispose() { _logoAnimationController.dispose(); _loadingAnimationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnnotatedRegion( value: SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light, statusBarBrightness: Brightness.dark, systemNavigationBarColor: AppTheme.primaryBlack, systemNavigationBarIconBrightness: Brightness.light, ), child: Scaffold( backgroundColor: AppTheme.primaryBlack, body: SafeArea( child: SizedBox( width: double.infinity, height: double.infinity, child: Stack( children: [ // Main content Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildLogo(), _buildLoadingIndicator(), ], ), ), // Version info _buildVersionInfo(), ], ), ), ), ), ); } }