// ===== lib/pages/splash_screen.dart MODIFIÉ AVEC API ===== import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../main.dart'; // Pour AuthController import '../widgets/wortis_logo.dart'; // NOUVEAU: Import du widget logo import 'login.dart'; import 'main_navigation.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override _SplashScreenState createState() => _SplashScreenState(); } class _SplashScreenState extends State with TickerProviderStateMixin { late AnimationController _logoController; late AnimationController _textController; late AnimationController _loadingController; late Animation _logoFadeAnimation; late Animation _logoScaleAnimation; late Animation _logoSlideAnimation; late Animation _textFadeAnimation; late Animation _textSlideAnimation; late Animation _loadingFadeAnimation; String _statusMessage = 'Initialisation...'; bool _hasApiConnection = false; // Couleurs Wortis static const Color primaryColor = Color(0xFF006699); static const Color secondaryColor = Color(0xFF0088CC); static const Color accentColor = Color(0xFFFF6B35); @override void initState() { super.initState(); _setupAnimations(); _startAnimationSequence(); _checkAuthStatus(); } void _setupAnimations() { _logoController = AnimationController( duration: Duration(milliseconds: 2000), vsync: this, ); _textController = AnimationController( duration: Duration(milliseconds: 1500), vsync: this, ); _loadingController = AnimationController( duration: Duration(milliseconds: 1200), vsync: this, ); _logoFadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _logoController, curve: Interval(0.0, 0.6, curve: Curves.easeOut), ), ); _logoScaleAnimation = Tween(begin: 0.3, end: 1.0).animate( CurvedAnimation( parent: _logoController, curve: Interval(0.0, 0.8, curve: Curves.elasticOut), ), ); _logoSlideAnimation = Tween( begin: Offset(0, -0.5), end: Offset.zero, ).animate( CurvedAnimation( parent: _logoController, curve: Interval(0.2, 1.0, curve: Curves.easeOutCubic), ), ); _textFadeAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation(parent: _textController, curve: Curves.easeOut)); _textSlideAnimation = Tween( begin: Offset(0, 0.3), end: Offset.zero, ).animate(CurvedAnimation(parent: _textController, curve: Curves.easeOut)); _loadingFadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _loadingController, curve: Curves.easeIn), ); } void _startAnimationSequence() async { _logoController.forward(); await Future.delayed(Duration(milliseconds: 800)); if (mounted) _textController.forward(); await Future.delayed(Duration(milliseconds: 400)); if (mounted) _loadingController.repeat(); } void _updateStatus(String message) { if (mounted) { setState(() { _statusMessage = message; }); } } void _checkAuthStatus() async { try { // Étape 1: Test de connexion API _updateStatus('Test de connexion API...'); await Future.delayed(Duration(milliseconds: 800)); if (!mounted) return; final authController = Provider.of( context, listen: false, ); // Tester la connexion à l'API _hasApiConnection = await authController.testApiConnection(); if (_hasApiConnection) { _updateStatus('API connectée ✓'); await Future.delayed(Duration(milliseconds: 600)); } else { _updateStatus('Mode hors ligne'); await Future.delayed(Duration(milliseconds: 600)); } // Étape 2: Vérification de l'authentification _updateStatus('Vérification de session...'); await Future.delayed(Duration(milliseconds: 800)); if (!mounted) return; bool isLoggedIn = await authController.checkLoginStatus(context); print('L\'utilisateur est : $isLoggedIn'); _updateStatus('Finalisation...'); await Future.delayed(Duration(milliseconds: 500)); if (!mounted) return; // Animation de sortie await _logoController.reverse(); if (!mounted) return; // Navigation Navigator.of(context).pushReplacement( PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) { return isLoggedIn ? MainNavigationPage(initialIndex: 0) : LoginPage(); }, transitionsBuilder: (context, animation, secondaryAnimation, child) { return FadeTransition( opacity: animation, child: SlideTransition( position: Tween( begin: Offset(0.0, 0.1), end: Offset.zero, ).animate( CurvedAnimation(parent: animation, curve: Curves.easeOut), ), child: child, ), ); }, transitionDuration: Duration(milliseconds: 600), ), ); } catch (e) { print('Erreur lors de la vérification d\'authentification: $e'); _updateStatus('Erreur de connexion'); await Future.delayed(Duration(seconds: 2)); if (mounted) { Navigator.of( context, ).pushReplacement(MaterialPageRoute(builder: (context) => LoginPage())); } } } void _showConnectionError() { if (mounted) { showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), title: Row( children: [ Icon(Icons.warning, color: Colors.orange), SizedBox(width: 8), Text('Connexion API'), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Impossible de se connecter au serveur Flask.\n', style: TextStyle(fontWeight: FontWeight.w500), ), Text('Vérifiez que :'), SizedBox(height: 8), Text('• Le serveur Flask est démarré'), Text('• MongoDB fonctionne'), Text('• L\'URL API est correcte'), Text('• Votre connexion réseau'), SizedBox(height: 12), Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8), ), child: Text( 'Vous pouvez continuer en mode hors ligne avec des données de démonstration.', style: TextStyle( fontSize: 13, color: Colors.grey.shade700, ), ), ), ], ), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); _checkAuthStatus(); // Réessayer }, child: Text('Réessayer'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (context) => LoginPage()), ); }, style: ElevatedButton.styleFrom( backgroundColor: primaryColor, ), child: Text( 'Continuer', style: TextStyle(color: Colors.white), ), ), ], ), ); } } @override void dispose() { _logoController.dispose(); _textController.dispose(); _loadingController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ primaryColor, primaryColor.withOpacity(0.8), secondaryColor, ], stops: [0.0, 0.6, 1.0], ), ), child: SafeArea( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Spacer(flex: 2), // Logo principal animé _buildAnimatedLogo(), SizedBox(height: 40), // Texte principal animé _buildAnimatedText(), Spacer(flex: 2), // Section loading avec statut API _buildLoadingSection(), SizedBox(height: 60), ], ), ), ), ), ); } Widget _buildAnimatedLogo() { return AnimatedBuilder( animation: _logoController, builder: (context, child) { return SlideTransition( position: _logoSlideAnimation, child: FadeTransition( opacity: _logoFadeAnimation, child: Transform.scale( scale: _logoScaleAnimation.value, child: WortisLogoWidget( size: 130, isWhite: true, // Logo blanc pour le fond bleu withShadow: true, ), ), ), ); }, ); } Widget _buildAnimatedText() { return AnimatedBuilder( animation: _textController, builder: (context, child) { return SlideTransition( position: _textSlideAnimation, child: FadeTransition( opacity: _textFadeAnimation, child: Column( children: [ Text( 'WORTIS', style: TextStyle( fontSize: 42, fontWeight: FontWeight.bold, color: Colors.white, letterSpacing: 8, shadows: [ Shadow( offset: Offset(0, 3), blurRadius: 6, color: Colors.black.withOpacity(0.4), ), ], ), ), SizedBox(height: 12), Text( 'Réseau Commercial', style: TextStyle( fontSize: 18, color: Colors.white.withOpacity(0.9), letterSpacing: 3, fontWeight: FontWeight.w300, shadows: [ Shadow( offset: Offset(0, 1), blurRadius: 3, color: Colors.black.withOpacity(0.3), ), ], ), ), SizedBox(height: 8), Container( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(20), border: Border.all( color: Colors.white.withOpacity(0.3), width: 1, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( _hasApiConnection ? Icons.cloud_done : Icons.cloud_off, color: Colors.white.withOpacity(0.8), size: 14, ), SizedBox(width: 6), Text( 'Agent Mobile App v1.0', style: TextStyle( fontSize: 13, color: Colors.white.withOpacity(0.8), letterSpacing: 1, fontWeight: FontWeight.w400, ), ), ], ), ), ], ), ), ); }, ); } Widget _buildLoadingSection() { return AnimatedBuilder( animation: _loadingController, builder: (context, child) { return FadeTransition( opacity: _loadingFadeAnimation, child: Column( children: [ Stack( alignment: Alignment.center, children: [ SizedBox( width: 50, height: 50, child: CircularProgressIndicator( strokeWidth: 3, valueColor: AlwaysStoppedAnimation( Colors.white.withOpacity(0.8), ), backgroundColor: Colors.white.withOpacity(0.2), ), ), Container( width: 8, height: 8, decoration: BoxDecoration( color: _hasApiConnection ? Colors.green : Colors.orange, shape: BoxShape.circle, ), ), ], ), SizedBox(height: 20), // Message de statut dynamique Text( _statusMessage, style: TextStyle( fontSize: 16, color: Colors.white.withOpacity(0.9), fontWeight: FontWeight.w300, letterSpacing: 1, ), ), SizedBox(height: 8), Text( 'Initialisation de votre espace agent', style: TextStyle( fontSize: 12, color: Colors.white.withOpacity(0.7), fontWeight: FontWeight.w300, ), ), if (!_hasApiConnection && _statusMessage.contains('hors ligne')) ...[ SizedBox(height: 12), Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.orange.withOpacity(0.2), borderRadius: BorderRadius.circular(16), border: Border.all(color: Colors.orange.withOpacity(0.3)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.wifi_off, color: Colors.white.withOpacity(0.8), size: 14, ), SizedBox(width: 6), Text( 'Mode démo', style: TextStyle( fontSize: 12, color: Colors.white.withOpacity(0.8), ), ), ], ), ), ], ], ), ); }, ); } }