import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:http/http.dart' as http; import 'package:intl/date_symbol_data_local.dart'; import 'package:provider/provider.dart'; import 'config/injection/injection.dart'; import 'config/router.dart'; import 'core/constants/env_config.dart'; import 'core/theme/theme_provider.dart'; import 'core/utils/app_logger.dart'; import 'data/datasources/event_remote_data_source.dart'; import 'data/datasources/notification_remote_data_source.dart'; import 'data/providers/friends_provider.dart'; import 'data/providers/presence_provider.dart'; import 'data/providers/user_provider.dart'; import 'data/repositories/friends_repository_impl.dart'; import 'data/services/notification_service.dart'; import 'data/services/preferences_helper.dart'; import 'data/services/realtime_notification_service.dart'; import 'data/services/secure_storage.dart'; import 'domain/entities/user.dart'; import 'presentation/state_management/event_bloc.dart'; import 'presentation/widgets/realtime_notification_handler.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Validation de la configuration au démarrage try { EnvConfig.validate(throwOnError: true); AppLogger.i('Configuration validée avec succès', tag: 'Main'); AppLogger.d(EnvConfig.getConfigSummary(), tag: 'Main'); } on ConfigurationException catch (e, stackTrace) { AppLogger.e( 'Erreur de configuration au démarrage', error: e, stackTrace: stackTrace, tag: 'Main', ); // En production, on ne peut pas continuer avec une configuration invalide if (EnvConfig.isProduction) { throw e; } // En développement, on continue mais on log l'erreur AppLogger.w('Continuité en mode développement malgré les erreurs de configuration', tag: 'Main'); } // Initialisation de l'injection de dépendances init(); // Initialisation du format de date en français await initializeDateFormatting('fr_FR'); // Récupération des services depuis GetIt final secureStorage = sl(); final preferencesHelper = sl(); // Récupération des informations stockées avec logs détaillés String? userId = await secureStorage.getUserId(); String? userFirstName = await preferencesHelper.getUseFirstrName(); String? userLastName = await preferencesHelper.getUserLastName(); // Log de la récupération des informations AppLogger.i( 'Récupération des informations utilisateur : userId = $userId, userFirstName = $userFirstName, userLastName = $userLastName', tag: 'Main', ); // Gestion des valeurs par défaut si les informations ne sont pas trouvées userId ??= 'default_user_id'; userFirstName ??= 'Default'; userLastName ??= 'User'; // Log des valeurs par défaut appliquées AppLogger.i( 'Valeurs par défaut appliquées : userId = $userId, userFirstName = $userFirstName, userLastName = $userLastName', tag: 'Main', ); // Création de l'objet User final User user = User( userId: userId, userLastName: userLastName, userFirstName: userFirstName, email: 'user@example.com', motDePasse: 'motDePasseHashé', profileImageUrl: 'lib/assets/images/profile_picture.png', ); runApp(MyApp(user: user)); } class MyApp extends StatefulWidget { const MyApp({ required this.user, super.key, }); final User user; @override State createState() => _MyAppState(); } class _MyAppState extends State { RealtimeNotificationService? _realtimeService; bool _isInitialized = false; @override void initState() { super.initState(); _initializeRealtime(); } /// Initialise le service de notifications temps réel. Future _initializeRealtime() async { try { // Vérifier si l'utilisateur est connecté (pas de valeur par défaut) if (widget.user.userId == 'default_user_id') { AppLogger.w('Utilisateur non connecté, service temps réel non initialisé', tag: 'MyApp'); setState(() => _isInitialized = true); return; } AppLogger.i('Initialisation du service temps réel pour userId: ${widget.user.userId}', tag: 'MyApp'); // Créer le service temps réel _realtimeService = RealtimeNotificationService(widget.user.userId); await _realtimeService!.connect(); AppLogger.i('Service temps réel connecté avec succès', tag: 'MyApp'); setState(() => _isInitialized = true); } catch (e, stackTrace) { AppLogger.e('Erreur lors de l\'initialisation du service temps réel', error: e, stackTrace: stackTrace, tag: 'MyApp'); setState(() => _isInitialized = true); } } /// Connecte le service temps réel aux providers après leur création. void _connectProvidersToRealtime(BuildContext context) { if (_realtimeService == null) return; try { // Connecter FriendsProvider final friendsProvider = Provider.of(context, listen: false); friendsProvider.connectRealtime(_realtimeService!); AppLogger.i('FriendsProvider connecté au service temps réel', tag: 'MyApp'); // Connecter PresenceProvider final presenceProvider = Provider.of(context, listen: false); presenceProvider.connectRealtime(_realtimeService!); AppLogger.i('PresenceProvider connecté au service temps réel', tag: 'MyApp'); // Connecter NotificationService final notificationService = Provider.of(context, listen: false); notificationService.connectRealtime(_realtimeService!); AppLogger.i('NotificationService connecté au service temps réel', tag: 'MyApp'); } catch (e, stackTrace) { AppLogger.e('Erreur lors de la connexion des providers au temps réel', error: e, stackTrace: stackTrace, tag: 'MyApp'); } } @override void dispose() { _realtimeService?.disconnect(); super.dispose(); } @override Widget build(BuildContext context) { // Récupération des dépendances depuis GetIt final friendsRepository = sl(); final notificationDataSource = sl(); final secureStorage = sl(); final eventRemoteDataSource = sl(); // Log lors de la construction de l'application AppLogger.i( "Construction de l'application avec user : ${widget.user.toString()}", tag: 'MyApp', ); return MultiProvider( providers: [ ChangeNotifierProvider( create: (_) => UserProvider()..setUser(widget.user), ), ChangeNotifierProvider( create: (_) => FriendsProvider(friendsRepository: friendsRepository), ), ChangeNotifierProvider( create: (_) => PresenceProvider(), ), ChangeNotifierProvider( create: (_) => ThemeProvider(), ), ChangeNotifierProvider( create: (_) => NotificationService(notificationDataSource, secureStorage) ..initialize(), ), BlocProvider( create: (context) => sl(), ), ], child: Consumer( builder: (context, themeProvider, _) { // Connecter les providers au service temps réel après leur création if (_isInitialized && _realtimeService != null) { WidgetsBinding.instance.addPostFrameCallback((_) { _connectProvidersToRealtime(context); }); } final materialApp = MaterialApp( title: 'AfterWork', theme: themeProvider.currentTheme, onGenerateRoute: AppRouter( eventRemoteDataSource: eventRemoteDataSource, userId: widget.user.userId, userFirstName: widget.user.userFirstName, userLastName: widget.user.userLastName, ).generateRoute, initialRoute: '/', ); // Wrapper avec RealtimeNotificationHandler si le service est initialisé if (_isInitialized && _realtimeService != null) { return RealtimeNotificationHandler( realtimeService: _realtimeService!, child: materialApp, ); } return materialApp; }, ), ); } }