import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:geosector_app/core/repositories/user_repository.dart'; import 'package:geosector_app/core/theme/app_theme.dart'; import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales import 'package:geosector_app/core/constants/app_keys.dart'; import 'package:geosector_app/core/data/models/user_model.dart'; import 'package:geosector_app/core/data/models/amicale_model.dart'; import 'package:geosector_app/core/data/models/client_model.dart'; import 'package:geosector_app/core/data/models/operation_model.dart'; import 'package:geosector_app/core/data/models/sector_model.dart'; import 'package:geosector_app/core/data/models/passage_model.dart'; import 'package:geosector_app/core/data/models/membre_model.dart'; import 'package:geosector_app/core/data/models/user_sector_model.dart'; import 'package:geosector_app/chat/models/conversation_model.dart'; import 'package:geosector_app/chat/models/message_model.dart'; import 'package:geosector_app/core/services/hive_reset_state_service.dart'; import 'package:geosector_app/presentation/widgets/clear_cache_dialog.dart'; import 'dart:async'; import 'dart:math' as math; class SplashPage extends StatefulWidget { const SplashPage({super.key}); @override State createState() => _SplashPageState(); } // Class pour dessiner les petits points blancs sur le fond class DotsPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.white.withOpacity(0.5) ..style = PaintingStyle.fill; final random = math.Random(42); // Seed fixe pour consistance final numberOfDots = (size.width * size.height) ~/ 1500; for (int i = 0; i < numberOfDots; i++) { final x = random.nextDouble() * size.width; final y = random.nextDouble() * size.height; final radius = 1.0 + random.nextDouble() * 2.0; canvas.drawCircle(Offset(x, y), radius, paint); } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; } class _SplashPageState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _scaleAnimation; bool _isInitializing = true; String _statusMessage = "Initialisation..."; double _progress = 0.0; bool _showButtons = false; final List _initializationSteps = [ "Initialisation des services...", "Vérification de l'authentification...", "Chargement des données..." ]; @override void initState() { super.initState(); // Animation controller sur 5 secondes (augmenté de 3 à 5 secondes) _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 5), ); // Animation de 4x la taille à 1x la taille (augmenté de 3x à 4x) _scaleAnimation = Tween( begin: 4.0, // Commencer à 4x la taille end: 1.0, // Terminer à la taille normale ).animate( CurvedAnimation( parent: _animationController, curve: Curves.easeOutBack, // Curve pour un effet de rebond ), ); // Démarrer l'animation immédiatement _animationController.forward(); // Vérifier si Hive a été réinitialisé _checkHiveReset(); // Simuler le processus d'initialisation _startInitialization(); } // Méthode pour vérifier si Hive a été réinitialisé et afficher le dialogue si nécessaire void _checkHiveReset() { // Vérifier si Hive a été réinitialisé et si le dialogue n'a pas encore été affiché if (hiveResetStateService.wasReset && !hiveResetStateService.dialogShown) { // Attendre que le widget soit complètement construit WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { // Afficher le dialogue de nettoyage du cache ClearCacheDialog.show( context, onClose: () { // Marquer le dialogue comme ayant été affiché hiveResetStateService.markDialogAsShown(); }, ); } }); } } @override void dispose() { _animationController.dispose(); super.dispose(); } void _startInitialization() async { // Étape 1: Initialisation des services if (mounted) { setState(() { _statusMessage = _initializationSteps[0]; _progress = 0.2; }); } // Initialiser toutes les boîtes Hive await _initializeAllHiveBoxes(); await Future.delayed(const Duration(milliseconds: 500)); // Étape 2: Vérification de l'authentification if (mounted) { setState(() { _statusMessage = _initializationSteps[1]; _progress = 0.4; }); } await Future.delayed(const Duration(milliseconds: 500)); // Étape 3: Chargement des données if (mounted) { setState(() { _statusMessage = _initializationSteps[2]; _progress = 1.0; // Directement à 100% après la 3ème étape }); } await Future.delayed(const Duration(milliseconds: 500)); if (mounted) { setState(() { _isInitializing = false; _showButtons = true; }); // Attendre quelques secondes avant de rediriger automatiquement // si l'utilisateur est déjà connecté if (userRepository.isLoggedIn) { Timer(const Duration(seconds: 2), () { _redirectToAppropriateScreen(); }); } } } // Méthode pour initialiser toutes les boîtes Hive Future _initializeAllHiveBoxes() async { try { debugPrint('Initialisation de toutes les boîtes Hive...'); // Structure pour les boîtes à ouvrir avec leurs noms d'affichage final boxesToOpen = [ {'name': AppKeys.usersBoxName, 'display': 'Préparation utilisateurs'}, {'name': AppKeys.amicaleBoxName, 'display': 'Préparation amicale'}, {'name': AppKeys.clientsBoxName, 'display': 'Préparation clients'}, {'name': AppKeys.regionsBoxName, 'display': 'Préparation régions'}, { 'name': AppKeys.operationsBoxName, 'display': 'Préparation opérations' }, {'name': AppKeys.sectorsBoxName, 'display': 'Préparation secteurs'}, {'name': AppKeys.passagesBoxName, 'display': 'Préparation passages'}, {'name': AppKeys.membresBoxName, 'display': 'Préparation membres'}, { 'name': AppKeys.userSectorBoxName, 'display': 'Préparation secteurs utilisateurs' }, {'name': AppKeys.settingsBoxName, 'display': 'Préparation paramètres'}, { 'name': AppKeys.chatConversationsBoxName, 'display': 'Préparation conversations' }, { 'name': AppKeys.chatMessagesBoxName, 'display': 'Préparation messages' }, ]; // Calculer l'incrément de progression pour chaque boîte final progressIncrement = 0.2 / boxesToOpen.length; double currentProgress = 0.0; // Ouvrir chaque boîte si elle n'est pas déjà ouverte for (int i = 0; i < boxesToOpen.length; i++) { final boxName = boxesToOpen[i]['name'] as String; final displayName = boxesToOpen[i]['display'] as String; // Mettre à jour la barre de progression et le message currentProgress += progressIncrement; if (mounted) { setState(() { _statusMessage = displayName; _progress = 0.2 * (currentProgress / 0.2); // Normaliser entre 0 et 0.2 }); } if (!Hive.isBoxOpen(boxName)) { debugPrint('Ouverture de la boîte $boxName ($displayName)...'); // Ouvrir la boîte avec le type approprié if (boxName == AppKeys.usersBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.amicaleBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.clientsBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.regionsBoxName) { // Ouvrir la boîte des régions sans type spécifique pour l'instant // car RegionModelAdapter n'est pas encore enregistré await Hive.openBox(boxName); } else if (boxName == AppKeys.operationsBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.sectorsBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.passagesBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.membresBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.userSectorBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.chatConversationsBoxName) { await Hive.openBox(boxName); } else if (boxName == AppKeys.chatMessagesBoxName) { await Hive.openBox(boxName); } else { await Hive.openBox(boxName); } debugPrint('Boîte $boxName ouverte avec succès'); } else { debugPrint('Boîte $boxName déjà ouverte'); } // Ajouter une temporisation entre chaque ouverture await Future.delayed(const Duration(milliseconds: 500)); } // Mettre à jour la barre de progression à 0.2 (20%) à la fin if (mounted) { setState(() { _statusMessage = 'Toutes les boîtes sont prêtes'; _progress = 0.2; }); } debugPrint('Toutes les boîtes Hive sont maintenant ouvertes'); } catch (e) { debugPrint('Erreur lors de l\'initialisation des boîtes Hive: $e'); // En cas d'erreur, mettre à jour le message if (mounted) { setState(() { _statusMessage = 'Erreur lors de l\'initialisation des données'; }); } } } void _redirectToAppropriateScreen() { if (!mounted) return; // Utiliser l'instance globale de userRepository définie dans app.dart if (userRepository.isLoggedIn) { debugPrint('SplashPage: Redirection d\'utilisateur connecté'); // Récupérer directement le rôle utilisateur final roleValue = userRepository.getUserRole(); debugPrint('SplashPage: Rôle utilisateur = $roleValue'); // Redirection simple basée sur le rôle if (roleValue > 1) { debugPrint('SplashPage: Redirection vers /admin (rôle $roleValue > 1)'); context.go('/admin'); } else { debugPrint('SplashPage: Redirection vers /user (rôle $roleValue = 1)'); context.go('/user'); } } // Ne redirige plus vers la landing page } @override Widget build(BuildContext context) { final theme = Theme.of(context); final size = MediaQuery.of(context).size; return Scaffold( body: Stack( children: [ // Fond dégradé avec petits points blancs AnimatedContainer( duration: const Duration(milliseconds: 500), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.white, Colors.blue.shade300], ), ), child: CustomPaint( painter: DotsPainter(), child: Container(width: double.infinity, height: double.infinity), ), ), // Contenu principal SafeArea( child: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 40), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Spacer(flex: 2), // Logo avec animation de réduction AnimatedBuilder( animation: _scaleAnimation, builder: (context, child) { return Transform.scale( scale: _scaleAnimation.value, child: child, ); }, child: Image.asset( 'assets/images/logo-geosector-1024.png', height: 180, // Augmenté de 140 à 180 ), ), const SizedBox(height: 24), // Titre avec animation fade-in AnimatedOpacity( opacity: _isInitializing ? 0.9 : 1.0, duration: const Duration(milliseconds: 500), child: Text( 'Geosector', style: theme.textTheme.headlineLarge?.copyWith( color: theme.colorScheme.primary, fontWeight: FontWeight.bold, letterSpacing: 1.2, ), ), ), const SizedBox(height: 16), // Sous-titre avec nouveau slogan AnimatedOpacity( opacity: _isInitializing ? 0.8 : 1.0, duration: const Duration(milliseconds: 500), child: Text( 'Une application puissante et intuitive de gestion de vos distributions de calendriers', textAlign: TextAlign.center, style: theme.textTheme.bodyLarge?.copyWith( color: theme.colorScheme.onBackground.withOpacity(0.7), fontWeight: FontWeight.w500, ), ), ), const Spacer(flex: 1), // Indicateur de chargement if (_isInitializing) ...[ Padding( padding: const EdgeInsets.symmetric(horizontal: 40), child: ClipRRect( borderRadius: BorderRadius.circular(8), child: LinearProgressIndicator( value: _progress, backgroundColor: Colors.grey.withOpacity(0.2), valueColor: AlwaysStoppedAnimation( theme.colorScheme.primary, ), minHeight: 10, // Augmenté de 6 à 10 ), ), ), const SizedBox(height: 16), Text( _statusMessage, style: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onBackground.withOpacity(0.7), ), ), ], // Boutons après l'initialisation if (_showButtons) ...[ // Bouton Connexion Utilisateur AnimatedOpacity( opacity: _showButtons ? 1.0 : 0.0, duration: const Duration(milliseconds: 500), child: ElevatedButton( onPressed: () { context.go('/login', extra: {'type': 'user'}); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.green, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 40, vertical: 16, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), elevation: 2, ), child: const Text( 'Connexion Utilisateur', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ), const SizedBox(height: 16), // Bouton Connexion Administrateur AnimatedOpacity( opacity: _showButtons ? 1.0 : 0.0, duration: const Duration(milliseconds: 500), child: ElevatedButton( onPressed: () { context.go('/login', extra: {'type': 'admin'}); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 40, vertical: 16, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), elevation: 2, ), child: const Text( 'Connexion Administrateur', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ), const SizedBox(height: 16), // Lien d'inscription AnimatedOpacity( opacity: _showButtons ? 1.0 : 0.0, duration: const Duration(milliseconds: 500), child: TextButton( onPressed: () { context.go('/register'); }, child: Text( 'Pas encore inscrit ?', style: TextStyle( color: theme.colorScheme.primary, fontWeight: FontWeight.w500, ), ), ), ), ], const Spacer(flex: 1), ], ), ), ), ), ], ), ); } }