// lib/main.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'dart:async'; // Import Timer import 'package:provider/single_child_widget.dart'; import 'package:environment_monitoring_app/services/api_service.dart'; import 'package:environment_monitoring_app/services/database_helper.dart'; import 'package:environment_monitoring_app/services/local_storage_service.dart'; import 'package:environment_monitoring_app/services/river_in_situ_sampling_service.dart'; import 'package:environment_monitoring_app/services/river_manual_triennial_sampling_service.dart'; // *** ADDED: Import River Investigative Sampling Service *** import 'package:environment_monitoring_app/services/river_investigative_sampling_service.dart'; import 'package:environment_monitoring_app/services/air_sampling_service.dart'; import 'package:environment_monitoring_app/services/telegram_service.dart'; import 'package:environment_monitoring_app/services/server_config_service.dart'; import 'package:environment_monitoring_app/services/retry_service.dart'; import 'package:environment_monitoring_app/services/marine_in_situ_sampling_service.dart'; import 'package:environment_monitoring_app/services/marine_investigative_sampling_service.dart'; import 'package:environment_monitoring_app/services/marine_npe_report_service.dart'; import 'package:environment_monitoring_app/services/marine_tarball_sampling_service.dart'; // Ensure this import is present import 'package:environment_monitoring_app/services/marine_manual_pre_departure_service.dart'; import 'package:environment_monitoring_app/services/marine_manual_sonde_calibration_service.dart'; import 'package:environment_monitoring_app/services/marine_manual_equipment_maintenance_service.dart'; import 'package:environment_monitoring_app/theme.dart'; import 'package:environment_monitoring_app/auth_provider.dart'; // Core Screens import 'package:environment_monitoring_app/screens/login.dart'; import 'package:environment_monitoring_app/screens/register.dart'; import 'package:environment_monitoring_app/screens/forgot_password.dart'; import 'package:environment_monitoring_app/screens/logout.dart'; import 'package:environment_monitoring_app/home_page.dart'; import 'package:environment_monitoring_app/screens/profile.dart'; import 'package:environment_monitoring_app/screens/settings.dart'; // --- START: New Settings Screen Imports --- import 'package:environment_monitoring_app/screens/settings/submission_preferences_settings.dart'; import 'package:environment_monitoring_app/screens/settings/telegram_alert_settings.dart'; import 'package:environment_monitoring_app/screens/settings/api_ftp_configurations_settings.dart'; import 'package:environment_monitoring_app/screens/settings/parameter_limits_settings.dart'; import 'package:environment_monitoring_app/screens/settings/air_clients_settings.dart'; import 'package:environment_monitoring_app/screens/settings/station_info_settings.dart'; // --- END: New Settings Screen Imports --- // Department Home Pages import 'package:environment_monitoring_app/screens/air/air_home_page.dart'; import 'package:environment_monitoring_app/screens/river/river_home_page.dart'; import 'package:environment_monitoring_app/screens/marine/marine_home_page.dart'; // Air Screens import 'package:environment_monitoring_app/screens/air/manual/air_manual_info_centre_document.dart'; import 'package:environment_monitoring_app/screens/air/manual/air_manual_installation_screen.dart'; import 'package:environment_monitoring_app/screens/air/manual/air_manual_collection_screen.dart'; import 'package:environment_monitoring_app/screens/air/manual/air_manual_report.dart' as airManualReport; import 'package:environment_monitoring_app/screens/air/manual/air_manual_data_status_log.dart' as airManualDataStatusLog; import 'package:environment_monitoring_app/screens/air/manual/air_manual_image_request.dart' as airManualImageRequest; import 'package:environment_monitoring_app/screens/air/continuous/air_continuous_info_centre_document.dart'; import 'package:environment_monitoring_app/screens/air/continuous/overview.dart' as airContinuousOverview; import 'package:environment_monitoring_app/screens/air/continuous/entry.dart' as airContinuousEntry; import 'package:environment_monitoring_app/screens/air/continuous/report.dart' as airContinuousReport; import 'package:environment_monitoring_app/screens/air/investigative/air_investigative_info_centre_document.dart'; import 'package:environment_monitoring_app/screens/air/investigative/overview.dart' as airInvestigativeOverview; import 'package:environment_monitoring_app/screens/air/investigative/entry.dart' as airInvestigativeEntry; import 'package:environment_monitoring_app/screens/air/investigative/report.dart' as airInvestigativeReport; // River Screens import 'package:environment_monitoring_app/screens/river/manual/river_manual_info_centre_document.dart'; import 'package:environment_monitoring_app/screens/river/manual/in_situ_sampling.dart' as riverManualInSituSampling; import 'package:environment_monitoring_app/screens/river/manual/river_manual_data_status_log.dart' as riverManualDataStatusLog; import 'package:environment_monitoring_app/screens/river/manual/river_manual_report.dart' as riverManualReport; import 'package:environment_monitoring_app/screens/river/manual/triennial/river_manual_triennial_sampling.dart' as riverManualTriennialSampling; import 'package:environment_monitoring_app/screens/river/manual/river_manual_image_request.dart' as riverManualImageRequest; import 'package:environment_monitoring_app/screens/river/continuous/river_continuous_info_centre_document.dart'; import 'package:environment_monitoring_app/screens/river/continuous/overview.dart' as riverContinuousOverview; import 'package:environment_monitoring_app/screens/river/continuous/entry.dart' as riverContinuousEntry; import 'package:environment_monitoring_app/screens/river/continuous/report.dart' as riverContinuousReport; import 'package:environment_monitoring_app/screens/river/investigative/river_investigative_info_centre_document.dart'; // *** ADDED: Import River Investigative Manual Sampling Screen *** import 'package:environment_monitoring_app/screens/river/investigative/river_investigative_manual_sampling.dart' as riverInvestigativeManualSampling; // *** START: ADDED NEW RIVER INVESTIGATIVE IMPORTS *** import 'package:environment_monitoring_app/screens/river/investigative/river_investigative_data_status_log.dart' as riverInvestigativeDataStatusLog; import 'package:environment_monitoring_app/screens/river/investigative/river_investigative_image_request.dart' as riverInvestigativeImageRequest; // *** END: ADDED NEW RIVER INVESTIGATIVE IMPORTS *** import 'package:environment_monitoring_app/screens/river/investigative/overview.dart' as riverInvestigativeOverview; import 'package:environment_monitoring_app/screens/river/investigative/entry.dart' as riverInvestigativeEntry; import 'package:environment_monitoring_app/screens/river/investigative/report.dart' as riverInvestigativeReport; // Marine Screens import 'package:environment_monitoring_app/screens/marine/manual/info_centre_document.dart' as marineManualInfoCentreDocument; import 'package:environment_monitoring_app/screens/marine/manual/marine_manual_pre_sampling.dart' as marineManualPreSampling; import 'package:environment_monitoring_app/screens/marine/manual/in_situ_sampling.dart' as marineManualInSituSampling; import 'package:environment_monitoring_app/screens/marine/manual/marine_manual_report.dart' as marineManualReport; import 'package:environment_monitoring_app/screens/marine/manual/reports/marine_manual_npe_report_hub.dart'; import 'package:environment_monitoring_app/screens/marine/manual/reports/marine_manual_pre_departure_checklist_screen.dart' as marineManualPreDepartureChecklist; import 'package:environment_monitoring_app/screens/marine/manual/reports/marine_manual_sonde_calibration_screen.dart' as marineManualSondeCalibration; import 'package:environment_monitoring_app/screens/marine/manual/reports/marine_manual_equipment_maintenance_screen.dart' as marineManualEquipmentMaintenance; import 'package:environment_monitoring_app/screens/marine/manual/marine_manual_data_status_log.dart' as marineManualDataStatusLog; // *** START: ADDED NEW IMPORT *** import 'package:environment_monitoring_app/screens/marine/manual/marine_manual_report_status_log.dart' as marineManualReportStatusLog; // *** END: ADDED NEW IMPORT *** import 'package:environment_monitoring_app/screens/marine/manual/marine_image_request.dart' as marineManualImageRequest; import 'package:environment_monitoring_app/screens/marine/continuous/marine_continuous_info_centre_document.dart'; import 'package:environment_monitoring_app/screens/marine/continuous/overview.dart' as marineContinuousOverview; import 'package:environment_monitoring_app/screens/marine/continuous/entry.dart' as marineContinuousEntry; import 'package:environment_monitoring_app/screens/marine/continuous/report.dart' as marineContinuousReport; import 'package:environment_monitoring_app/screens/marine/investigative/marine_investigative_info_centre_document.dart'; import 'package:environment_monitoring_app/screens/marine/investigative/marine_investigative_manual_sampling.dart' as marineInvestigativeManualSampling; // *** START: ADDED NEW MARINE INVESTIGATIVE IMPORTS *** import 'package:environment_monitoring_app/screens/marine/investigative/marine_investigative_data_status_log.dart' as marineInvestigativeDataStatusLog; import 'package:environment_monitoring_app/screens/marine/investigative/marine_investigative_image_request.dart' as marineInvestigativeImageRequest; // *** END: ADDED NEW MARINE INVESTIGATIVE IMPORTS *** import 'package:environment_monitoring_app/screens/marine/investigative/overview.dart' as marineInvestigativeOverview; import 'package:environment_monitoring_app/screens/marine/investigative/entry.dart' as marineInvestigativeEntry; import 'package:environment_monitoring_app/screens/marine/investigative/report.dart' as marineInvestigativeReport; import 'package:environment_monitoring_app/models/tarball_data.dart'; import 'package:environment_monitoring_app/screens/marine/manual/tarball_sampling_step1.dart'; import 'package:environment_monitoring_app/screens/marine/manual/tarball_sampling_step2.dart'; import 'package:environment_monitoring_app/screens/marine/manual/tarball_sampling_step3_summary.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Create singleton instances of core services before running the app final DatabaseHelper databaseHelper = DatabaseHelper(); final TelegramService telegramService = TelegramService(); final ApiService apiService = ApiService(telegramService: telegramService); final RetryService retryService = RetryService(); final MarineInSituSamplingService marineInSituService = MarineInSituSamplingService(telegramService); final RiverInSituSamplingService riverInSituService = RiverInSituSamplingService(telegramService); final MarineInvestigativeSamplingService marineInvestigativeService = MarineInvestigativeSamplingService(telegramService); // *** ADDED: Create instance of RiverInvestigativeSamplingService *** final RiverInvestigativeSamplingService riverInvestigativeService = RiverInvestigativeSamplingService(telegramService); final MarineTarballSamplingService marineTarballService = MarineTarballSamplingService(telegramService); telegramService.setApiService(apiService); // The AuthProvider needs to be created here so it can be passed to the retry service. final authProvider = AuthProvider( apiService: apiService, dbHelper: databaseHelper, serverConfigService: ServerConfigService(), retryService: retryService, ); // Initialize the retry service with all its dependencies. // *** MODIFIED: Added riverInvestigativeService dependency (and marineTarballService from previous request) *** retryService.initialize( marineInSituService: marineInSituService, riverInSituService: riverInSituService, marineInvestigativeService: marineInvestigativeService, riverInvestigativeService: riverInvestigativeService, // <-- Added this line marineTarballService: marineTarballService, authProvider: authProvider, ); setupPeriodicServices(telegramService, retryService); runApp( MultiProvider( providers: [ ChangeNotifierProvider.value(value: authProvider), Provider(create: (_) => apiService), Provider(create: (_) => databaseHelper), Provider(create: (_) => telegramService), Provider(create: (_) => LocalStorageService()), Provider.value(value: retryService), Provider.value(value: marineInSituService), Provider.value(value: marineInvestigativeService), Provider.value(value: riverInSituService), // *** ADDED: Provider for River Investigative Service *** Provider.value(value: riverInvestigativeService), // Use Provider.value Provider(create: (context) => RiverManualTriennialSamplingService(telegramService)), Provider(create: (context) => AirSamplingService(databaseHelper, telegramService)), Provider.value(value: marineTarballService), // Use Provider.value Provider(create: (context) => MarineNpeReportService(Provider.of(context, listen: false))), Provider( create: (context) => MarineManualPreDepartureService(Provider.of(context, listen: false))), Provider( create: (context) => MarineManualSondeCalibrationService(Provider.of(context, listen: false))), Provider( create: (context) => MarineManualEquipmentMaintenanceService(Provider.of(context, listen: false))), ], child: const RootApp(), ), ); } void setupPeriodicServices(TelegramService telegramService, RetryService retryService) { // Initial processing on startup (delayed) Future.delayed(const Duration(seconds: 5), () { debugPrint("[Main] Performing initial alert queue processing on app start."); telegramService.processAlertQueue(); debugPrint("[Main] Performing initial retry queue processing on app start."); retryService.processRetryQueue(); }); // Start recurring timers to process both queues every 5 minutes. Timer.periodic(const Duration(minutes: 5), (timer) { debugPrint("[Main] Periodic check: Processing Telegram alert queue..."); telegramService.processAlertQueue(); debugPrint("[Main] Periodic check: Processing main retry queue..."); retryService.processRetryQueue(); }); } class RootApp extends StatefulWidget { const RootApp({super.key}); @override State createState() => _RootAppState(); } class _RootAppState extends State { // --- START: MODIFICATION FOR HOURLY SYNC --- Timer? _configSyncTimer; // --- END: MODIFICATION --- @override void initState() { super.initState(); _initializeConnectivityListener(); _performInitialSessionCheck(); // --- START: MODIFICATION FOR HOURLY SYNC --- _initializePeriodicSync(); // Start the hourly sync timer // --- END: MODIFICATION --- } // --- START: MODIFICATION FOR HOURLY SYNC --- @override void dispose() { _configSyncTimer?.cancel(); // Cancel the timer when the app closes super.dispose(); } // --- END: MODIFICATION --- /// Initial check when app loads to see if we need to transition from offline to online. void _performInitialSessionCheck() async { // Wait a moment for providers to be fully available. await Future.delayed(const Duration(milliseconds: 100)); if (mounted) { final authProvider = Provider.of(context, listen: false); // Perform proactive token refresh on app start await authProvider.proactiveTokenRefresh(); // First, try to transition from an offline placeholder token to an online one. final didTransition = await authProvider.checkAndTransitionToOnlineSession(); // If no transition happened (i.e., we were already supposed to be online), validate the session. if (!didTransition) { authProvider.validateAndRefreshSession(); } } } /// Listens for connectivity changes to trigger auto-relogin or queue processing. void _initializeConnectivityListener() { Connectivity().onConnectivityChanged.listen((List results) { if (!results.contains(ConnectivityResult.none)) { debugPrint("[Main] Internet connection detected."); if (mounted) { // Access services from provider context final authProvider = Provider.of(context, listen: false); final telegramService = Provider.of(context, listen: false); final retryService = Provider.of(context, listen: false); // When connection is restored, always try to transition/validate the session. authProvider.checkAndTransitionToOnlineSession().then((didTransition) { if (!didTransition) { authProvider.validateAndRefreshSession(); } }); // Process queues telegramService.processAlertQueue(); retryService.processRetryQueue(); } } else { debugPrint("[Main] Internet connection lost."); } }); } // --- START: MODIFICATION FOR HOURLY SYNC --- /// Initializes a recurring timer to sync data periodically. void _initializePeriodicSync() { // Start a timer for 1 hour (as requested). You can change this duration. _configSyncTimer = Timer.periodic(const Duration(hours: 1), (timer) { debugPrint("[Main] Periodic 1-hour sync triggered."); // Use 'context.read' for a safe, one-time read inside a timer if (mounted) { final authProvider = context.read(); // Only sync if the user is logged in and the session isn't expired if (authProvider.isLoggedIn && !authProvider.isSessionExpired) { debugPrint("[Main] User is logged in. Starting periodic data sync..."); // Run syncAllData but don't block. Catch errors to prevent the timer from stopping. authProvider.syncAllData().catchError((e) { debugPrint("[Main] Error during periodic 1-hour sync: $e"); }); } else { debugPrint("[Main] Skipping periodic sync: User not logged in or session expired."); } } }); } // --- END: MODIFICATION --- @override Widget build(BuildContext context) { return Consumer( builder: (context, auth, child) { Widget homeWidget; if (auth.isLoading) { homeWidget = const SplashScreen(); } else if (auth.isLoggedIn) { homeWidget = const SessionAwareWrapper(child: HomePage()); } else { homeWidget = const LoginScreen(); } return MaterialApp( title: 'Environment Monitoring App', theme: AppTheme.darkBlueTheme, debugShowCheckedModeBanner: false, home: homeWidget, onGenerateRoute: (settings) { // Keep existing onGenerateRoute logic for Tarball if (settings.name == '/marine/manual/tarball/step2') { final args = settings.arguments as TarballSamplingData; return MaterialPageRoute(builder: (context) { return TarballSamplingStep2(data: args); }); } if (settings.name == '/marine/manual/tarball/step3') { final args = settings.arguments as TarballSamplingData; return MaterialPageRoute(builder: (context) { return TarballSamplingStep3Summary(data: args); }); } if (settings.name == '/marine/manual/data-log') { return MaterialPageRoute(builder: (context) { return const marineManualDataStatusLog.MarineManualDataStatusLog(); }); } // Add other potential dynamic routes here if necessary return null; // Let routes map handle named routes }, routes: { // Auth Routes '/register': (context) => const RegisterScreen(), '/forgot-password': (context) => ForgotPasswordScreen(), '/logout': (context) => const LogoutScreen(), '/home': (context) => const HomePage(), '/profile': (context) => const ProfileScreen(), '/settings': (context) => const SettingsScreen(), // --- START: New Settings Routes (const removed) --- '/settings/submission-prefs': (context) => SubmissionPreferencesSettingsScreen(), '/settings/telegram-alerts': (context) => TelegramAlertSettingsScreen(), '/settings/api-ftp-configs': (context) => ApiFtpConfigurationsSettingsScreen(), '/settings/parameter-limits': (context) => ParameterLimitsSettingsScreen(), '/settings/air-clients': (context) => AirClientsSettingsScreen(), '/settings/station-info': (context) => StationInfoSettingsScreen(), // --- END: New Settings Routes --- // Department Home Pages '/air/home': (context) => const AirHomePage(), '/river/home': (context) => const RiverHomePage(), '/marine/home': (context) => const MarineHomePage(), // Air Manual '/air/manual/info': (context) => const AirManualInfoCentreDocument(), '/air/manual/installation': (context) => const AirManualInstallationScreen(), '/air/manual/collection': (context) => const AirManualCollectionScreen(), '/air/manual/report': (context) => airManualReport.AirManualReport(), '/air/manual/data-log': (context) => airManualDataStatusLog.AirManualDataStatusLog(), '/air/manual/image-request': (context) => airManualImageRequest.AirManualImageRequest(), // Air Continuous '/air/continuous/info': (context) => const AirContinuousInfoCentreDocument(), '/air/continuous/overview': (context) => airContinuousOverview.OverviewScreen(), '/air/continuous/entry': (context) => airContinuousEntry.EntryScreen(), '/air/continuous/report': (context) => airContinuousReport.ReportScreen(), // Air Investigative '/air/investigative/info': (context) => const AirInvestigativeInfoCentreDocument(), '/air/investigative/overview': (context) => airInvestigativeOverview.OverviewScreen(), '/air/investigative/entry': (context) => airInvestigativeEntry.EntryScreen(), '/air/investigative/report': (context) => airInvestigativeReport.ReportScreen(), // River Manual '/river/manual/info': (context) => const RiverManualInfoCentreDocument(), '/river/manual/in-situ': (context) => riverManualInSituSampling.RiverInSituSamplingScreen(), '/river/manual/report': (context) => riverManualReport.RiverManualReport(), '/river/manual/triennial': (context) => riverManualTriennialSampling.RiverManualTriennialSamplingScreen(), '/river/manual/data-log': (context) => riverManualDataStatusLog.RiverManualDataStatusLog(), '/river/manual/image-request': (context) => riverManualImageRequest.RiverManualImageRequest(), // River Continuous '/river/continuous/info': (context) => const RiverContinuousInfoCentreDocument(), '/river/continuous/overview': (context) => riverContinuousOverview.OverviewScreen(), '/river/continuous/entry': (context) => riverContinuousEntry.EntryScreen(), '/river/continuous/report': (context) => riverContinuousReport.ReportScreen(), // River Investigative '/river/investigative/info': (context) => const RiverInvestigativeInfoCentreDocument(), // *** ADDED: Route for River Investigative Manual Sampling *** '/river/investigative/manual-sampling': (context) => riverInvestigativeManualSampling.RiverInvestigativeManualSamplingScreen(), // *** START: ADDED NEW RIVER INVESTIGATIVE ROUTES *** '/river/investigative/data-log': (context) => const riverInvestigativeDataStatusLog.RiverInvestigativeDataStatusLog(), '/river/investigative/image-request': (context) => const riverInvestigativeImageRequest.RiverInvestigativeImageRequest(), // *** END: ADDED NEW RIVER INVESTIGATIVE ROUTES *** '/river/investigative/overview': (context) => riverInvestigativeOverview.OverviewScreen(), // Keep placeholder/future routes '/river/investigative/entry': (context) => riverInvestigativeEntry.EntryScreen(), // Keep placeholder/future routes '/river/investigative/report': (context) => riverInvestigativeReport.ReportScreen(), // Keep placeholder/future routes // Marine Manual '/marine/manual/info': (context) => marineManualInfoCentreDocument.MarineInfoCentreDocument(), '/marine/manual/pre-sampling': (context) => marineManualPreSampling.MarineManualPreSampling(), '/marine/manual/in-situ': (context) => marineManualInSituSampling.MarineInSituSampling(), '/marine/manual/tarball': (context) => const TarballSamplingStep1(), '/marine/manual/report': (context) => const marineManualReport.MarineManualReportHomePage(), '/marine/manual/report/npe': (context) => const MarineManualNPEReportHub(), '/marine/manual/report/pre-departure': (context) => const marineManualPreDepartureChecklist.MarineManualPreDepartureChecklistScreen(), '/marine/manual/report/calibration': (context) => const marineManualSondeCalibration.MarineManualSondeCalibrationScreen(), '/marine/manual/report/maintenance': (context) => const marineManualEquipmentMaintenance.MarineManualEquipmentMaintenanceScreen(), '/marine/manual/image-request': (context) => const marineManualImageRequest.MarineImageRequestScreen(), // *** START: ADDED NEW ROUTE *** '/marine/manual/report-log': (context) => const marineManualReportStatusLog.MarineManualReportStatusLog(), // *** END: ADDED NEW ROUTE *** // Marine Continuous '/marine/continuous/info': (context) => const MarineContinuousInfoCentreDocument(), '/marine/continuous/overview': (context) => marineContinuousOverview.OverviewScreen(), '/marine/continuous/entry': (context) => marineContinuousEntry.EntryScreen(), '/marine/continuous/report': (context) => marineContinuousReport.ReportScreen(), // Marine Investigative '/marine/investigative/info': (context) => const MarineInvestigativeInfoCentreDocument(), '/marine/investigative/manual-sampling': (context) => marineInvestigativeManualSampling.MarineInvestigativeManualSampling(), // *** START: ADDED NEW MARINE INVESTIGATIVE ROUTES *** '/marine/investigative/data-log': (context) => const marineInvestigativeDataStatusLog.MarineInvestigativeDataStatusLog(), '/marine/investigative/image-request': (context) => const marineInvestigativeImageRequest.MarineInvestigativeImageRequestScreen(), // *** END: ADDED NEW MARINE INVESTIGATIVE ROUTES *** '/marine/investigative/overview': (context) => marineInvestigativeOverview.OverviewScreen(), '/marine/investigative/entry': (context) => marineInvestigativeEntry.EntryScreen(), '/marine/investigative/report': (context) => marineInvestigativeReport.ReportScreen(), }, ); }, ); } } class SessionAwareWrapper extends StatefulWidget { final Widget child; const SessionAwareWrapper({super.key, required this.child}); @override State createState() => _SessionAwareWrapperState(); } class _SessionAwareWrapperState extends State { bool _isDialogShowing = false; // --- MODIFICATION START --- // 1. Create a variable to hold the AuthProvider instance. late AuthProvider _authProvider; // --- MODIFICATION END --- @override void didChangeDependencies() { super.didChangeDependencies(); // --- MODIFICATION START --- // 2. Get the provider reference here and add the listener. _authProvider = Provider.of(context); _authProvider.addListener(_handleSessionExpired); // --- MODIFICATION END --- // Call initial check here if needed, or rely on RootApp's check. _checkAndShowDialogIfNeeded(_authProvider.isSessionExpired); } @override void dispose() { // --- MODIFICATION START --- // 3. Use the saved reference to remove the listener. This is safe. _authProvider.removeListener(_handleSessionExpired); // --- MODIFICATION END --- super.dispose(); } void _handleSessionExpired() { // --- MODIFICATION START --- // 4. Use the saved _authProvider reference. _checkAndShowDialogIfNeeded(_authProvider.isSessionExpired); // --- MODIFICATION END --- } void _checkAndShowDialogIfNeeded(bool isExpired) { if (isExpired && !_isDialogShowing && mounted) { WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && !_isDialogShowing) { // Double check mounted and flag _showSessionExpiredDialog(); } }); } else if (!isExpired && _isDialogShowing && mounted) { // If session becomes valid again and dialog is showing, maybe dismiss it? // Or rely on user action. For now, we only trigger ON expiry. } } Future _showSessionExpiredDialog() async { if (!mounted) return; setState(() => _isDialogShowing = true); await showDialog( context: context, barrierDismissible: false, builder: (BuildContext dialogContext) { // Use the state's _authProvider reference, which is safe. return AlertDialog( title: const Text("Session Expired"), content: const Text( "Your online session has expired. You can continue working offline, but you will not be able to sync data until you log in again."), actions: [ TextButton( child: const Text("Continue Offline"), onPressed: () { Navigator.of(dialogContext).pop(); // Optionally: _authProvider.clearSessionExpiredFlag(); // If needed }, ), ElevatedButton( child: const Text("Login Now"), onPressed: () { // --- MODIFICATION START --- // 5. Use the saved reference to log out. _authProvider.logout(); // --- MODIFICATION END --- Navigator.of(dialogContext).pop(); // Close dialog first // RootApp builder will handle navigation to LoginScreen }, ), ], ); }, ); // Reset flag after dialog is dismissed if (mounted) { setState(() => _isDialogShowing = false); } } @override Widget build(BuildContext context) { return widget.child; } } class SplashScreen extends StatelessWidget { const SplashScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( 'assets/icon4.png', // Ensure this asset exists height: 360, width: 360, ), const SizedBox(height: 24), const CircularProgressIndicator(), const SizedBox(height: 20), const Text('Loading MMS data...', style: TextStyle(fontSize: 16)), ], ), ), ); } }