import 'dart:io'; import 'dart:math' as math; import 'package:base_project/core/constants/ui_constants.dart'; import 'package:base_project/view_model/splash_view_model.dart'; import 'package:base_project/view_model/system_params/system_params_view_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../core/providers/dynamic_theme_provider.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override State createState() => _SplashScreenState(); } class _SplashScreenState extends State with TickerProviderStateMixin { late AnimationController _logoController; late AnimationController _textController; late AnimationController _particleController; late AnimationController _progressController; late Animation _logoScale; late Animation _logoOpacity; late Animation _textOpacity; late Animation _textSlide; late Animation _progressValue; late Animation _particleRotation; @override void initState() { super.initState(); _initializeAnimations(); _startSplashSequence(); } @override void didChangeDependencies() { super.didChangeDependencies(); // Listen to dynamic theme changes to ensure colors update final dynamicThemeProvider = Provider.of(context, listen: false); dynamicThemeProvider.addListener(_onThemeChanged); } void _onThemeChanged() { // Force rebuild when dynamic theme changes if (mounted) { print('Splash Screen: Theme changed, rebuilding...'); setState(() {}); } } // Method to force refresh colors (can be called externally if needed) void refreshColors() { if (mounted) { print('Splash Screen: Colors refreshed manually'); setState(() {}); } } void _initializeAnimations() { // Logo animation controller _logoController = AnimationController( duration: UIConstants.durationSlow, vsync: this, ); // Text animation controller _textController = AnimationController( duration: UIConstants.durationNormal, vsync: this, ); // Particle animation controller _particleController = AnimationController( duration: const Duration(seconds: 3), vsync: this, ); // Progress animation controller _progressController = AnimationController( duration: const Duration(seconds: 3), vsync: this, ); // Logo animations _logoScale = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _logoController, curve: Curves.elasticOut, )); _logoOpacity = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _logoController, curve: Curves.easeInOut, )); // Text animations _textOpacity = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _textController, curve: Curves.easeInOut, )); _textSlide = Tween( begin: 50.0, end: 0.0, ).animate(CurvedAnimation( parent: _textController, curve: Curves.easeOutCubic, )); // Progress animation _progressValue = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _progressController, curve: Curves.easeInOut, )); // Particle rotation _particleRotation = Tween( begin: 0.0, end: 2 * math.pi, ).animate(CurvedAnimation( parent: _particleController, curve: Curves.linear, )); } void _startSplashSequence() async { // Start logo animation await _logoController.forward(); // Start text animation await Future.delayed(const Duration(milliseconds: 300)); _textController.forward(); // Start progress and particle animations await Future.delayed(const Duration(milliseconds: 200)); _progressController.forward(); _particleController.repeat(); // Check navigation after animations SplashViewModel().checkNavigation(context); } @override void dispose() { // Remove listener before disposing try { final dynamicThemeProvider = Provider.of(context, listen: false); dynamicThemeProvider.removeListener(_onThemeChanged); } catch (e) { // Provider might not be available during dispose } _logoController.dispose(); _textController.dispose(); _particleController.dispose(); _progressController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // Always use dynamic theme provider for consistent colors return Consumer( builder: (context, dynamicThemeProvider, child) { // Get the current dynamic color scheme final colorScheme = dynamicThemeProvider.getCurrentColorScheme( Theme.of(context).brightness == Brightness.dark); // Debug information for theme tracking if (dynamicThemeProvider.isUsingDynamicTheme) { print( 'Splash Screen: Using dynamic theme with primary color: ${colorScheme.primary}'); } else { print( 'Splash Screen: Using default theme with primary color: ${colorScheme.primary}'); } return Scaffold( body: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ colorScheme.primary, colorScheme.primaryContainer, colorScheme.secondary, ], stops: const [0.0, 0.5, 1.0], ), ), child: Stack( children: [ // Animated background particles _buildParticleBackground(), // Main content SafeArea( child: Padding( padding: UIConstants.screenPaddingLarge, child: Column( children: [ // Top section with logo Expanded( flex: 3, child: _buildLogoSection(colorScheme), ), // Middle section with text Expanded( flex: 2, child: _buildTextSection(colorScheme), ), // Bottom section with progress Expanded( flex: 1, child: _buildProgressSection(colorScheme), ), ], ), ), ), ], ), ), ); }, ); } Widget _buildParticleBackground() { return Consumer( builder: (context, dynamicThemeProvider, child) { final colorScheme = dynamicThemeProvider.getCurrentColorScheme( Theme.of(context).brightness == Brightness.dark); return AnimatedBuilder( animation: _particleRotation, builder: (context, child) { return CustomPaint( painter: ParticlePainter( rotation: _particleRotation.value, color: colorScheme.primary.withOpacity(0.15), ), size: Size.infinite, ); }, ); }, ); } Widget _buildLogoSection(ColorScheme colorScheme) { return Center( child: AnimatedBuilder( animation: _logoController, builder: (context, child) { return Transform.scale( scale: _logoScale.value, child: Opacity( opacity: _logoOpacity.value, child: Container( width: UIConstants.logoSizeXLarge * 2, height: UIConstants.logoSizeXLarge * 2, decoration: BoxDecoration( shape: BoxShape.circle, color: colorScheme.surface.withOpacity(0.2), border: Border.all( color: colorScheme.primary.withOpacity(0.3), width: 2, ), boxShadow: [ BoxShadow( color: colorScheme.primary.withOpacity(0.2), blurRadius: 20, spreadRadius: 5, ), BoxShadow( color: colorScheme.secondary.withOpacity(0.1), blurRadius: 40, spreadRadius: 10, ), ], ), child: Center( child: Consumer( builder: (context, provider, _) { if (provider.profileImg != null) { return ClipOval( child: Image.file( File(provider.profileImg!.path), fit: BoxFit.cover, width: UIConstants.logoSizeXLarge * 1.5, height: UIConstants.logoSizeXLarge * 1.5, ), ); } else { return Icon( Icons.security, size: UIConstants.logoSizeXLarge, color: colorScheme.onSurface, ); } }, ), ), ), ), ); }, ), ); } Widget _buildTextSection(ColorScheme colorScheme) { return AnimatedBuilder( animation: _textController, builder: (context, child) { return Transform.translate( offset: Offset(0, _textSlide.value), child: Opacity( opacity: _textOpacity.value, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "AuthSec", style: Theme.of(context).textTheme.displayLarge?.copyWith( color: colorScheme.onSurface, fontWeight: FontWeight.bold, letterSpacing: 2.0, ), ), const SizedBox(height: UIConstants.spacing16), Text( "Secure Authentication System", style: Theme.of(context).textTheme.titleLarge?.copyWith( color: colorScheme.onSurface.withOpacity(0.9), fontWeight: FontWeight.w300, letterSpacing: 1.0, ), ), const SizedBox(height: UIConstants.spacing24), Container( padding: UIConstants.cardPaddingMedium, decoration: BoxDecoration( color: colorScheme.surface.withOpacity(0.2), borderRadius: BorderRadius.circular(UIConstants.radius20), border: Border.all( color: colorScheme.primary.withOpacity(0.3), width: 1, ), boxShadow: [ BoxShadow( color: colorScheme.primary.withOpacity(0.1), blurRadius: 10, spreadRadius: 2, ), ], ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.shield, color: colorScheme.primary, size: UIConstants.iconSizeMedium, ), const SizedBox(width: UIConstants.spacing12), Text( "Enterprise Security", style: Theme.of(context).textTheme.titleMedium?.copyWith( color: colorScheme.onSurface, fontWeight: FontWeight.w500, ), ), ], ), ), ], ), ), ); }, ); } Widget _buildProgressSection(ColorScheme colorScheme) { return AnimatedBuilder( animation: _progressController, builder: (context, child) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Progress bar Container( width: double.infinity, height: 4, decoration: BoxDecoration( color: colorScheme.surface.withOpacity(0.3), borderRadius: BorderRadius.circular(UIConstants.radiusFull), border: Border.all( color: colorScheme.primary.withOpacity(0.2), width: 1, ), ), child: FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: _progressValue.value, child: Container( decoration: BoxDecoration( color: colorScheme.primary, borderRadius: BorderRadius.circular(UIConstants.radiusFull), boxShadow: [ BoxShadow( color: colorScheme.primary.withOpacity(0.5), blurRadius: 10, spreadRadius: 2, ), ], ), ), ), ), const SizedBox(height: UIConstants.spacing16), Text( "Initializing...", style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: colorScheme.onSurface.withOpacity(0.8), fontWeight: FontWeight.w400, ), ), ], ); }, ); } } class ParticlePainter extends CustomPainter { final double rotation; final Color color; ParticlePainter({required this.rotation, required this.color}); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = color ..style = PaintingStyle.fill; final center = Offset(size.width / 2, size.height / 2); final radius = math.min(size.width, size.height) / 3; // Draw rotating particles for (int i = 0; i < 8; i++) { final angle = (i * math.pi / 4) + rotation; final x = center.dx + radius * math.cos(angle); final y = center.dy + radius * math.sin(angle); canvas.drawCircle( Offset(x, y), 3, paint, ); } } @override bool shouldRepaint(ParticlePainter oldDelegate) => true; }