// lib/main.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:provider/single_child_widget.dart'; import 'package:environment_monitoring_app/services/api_service.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/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_tarball_sampling_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'; // 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; // MODIFIED: Import paths updated to new filenames import 'package:environment_monitoring_app/screens/river/manual/river_manual_report.dart' as riverManualReport; import 'package:environment_monitoring_app/screens/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'; 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/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/marine_manual_npe_report.dart' as marineManualNPEReport; import 'package:environment_monitoring_app/screens/marine/manual/marine_manual_data_status_log.dart' as marineManualDataStatusLog; 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/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); telegramService.setApiService(apiService); setupServices(telegramService); runApp( MultiProvider( providers: [ ChangeNotifierProvider( create: (context) => AuthProvider( apiService: apiService, dbHelper: databaseHelper, serverConfigService: ServerConfigService(), retryService: RetryService(), ), ), // Providers for core services Provider(create: (_) => apiService), Provider(create: (_) => databaseHelper), Provider(create: (_) => telegramService), Provider(create: (_) => LocalStorageService()), Provider(create: (context) => RiverInSituSamplingService(telegramService)), Provider(create: (context) => AirSamplingService(databaseHelper, telegramService)), Provider(create: (context) => MarineInSituSamplingService(telegramService)), Provider(create: (context) => MarineTarballSamplingService(telegramService)), ], child: const RootApp(), ), ); } void setupServices(TelegramService telegramService) { // Initial alert processing on startup (delayed) Future.delayed(const Duration(seconds: 5), () { debugPrint("[Main] Performing initial alert queue processing on app start."); telegramService.processAlertQueue(); }); // Connectivity listener moved to RootApp to access AuthProvider context. } // --- START: MODIFIED RootApp --- class RootApp extends StatefulWidget { const RootApp({super.key}); @override State createState() => _RootAppState(); } class _RootAppState extends State { @override void initState() { super.initState(); _initializeConnectivityListener(); _performInitialSessionCheck(); } /// 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) { Provider.of(context, listen: false).checkAndTransitionToOnlineSession(); } } /// 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); // Attempt to auto-relogin if necessary authProvider.checkAndTransitionToOnlineSession(); // Process alert queue telegramService.processAlertQueue(); } } else { debugPrint("[Main] Internet connection lost."); } }); } @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 HomePage(); } else { homeWidget = const LoginScreen(); } return MaterialApp( title: 'Environment Monitoring App', theme: AppTheme.darkBlueTheme, debugShowCheckedModeBanner: false, home: homeWidget, onGenerateRoute: (settings) { 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(); }); } return null; }, 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(), // 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(), // MODIFIED: Routes updated to use new class names from aliased imports '/river/manual/report': (context) => riverManualReport.RiverManualReport(), '/river/manual/triennial': (context) => riverManualTriennialSampling.RiverTriennialSampling(), '/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(), '/river/investigative/overview': (context) => riverInvestigativeOverview.OverviewScreen(), '/river/investigative/entry': (context) => riverInvestigativeEntry.EntryScreen(), '/river/investigative/report': (context) => riverInvestigativeReport.ReportScreen(), // Marine Manual '/marine/manual/info': (context) => marineManualInfoCentreDocument.MarineInfoCentreDocument(), '/marine/manual/pre-sampling': (context) => marineManualPreSampling.MarinePreSampling(), '/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 marineManualNPEReport.MarineManualNPEReport(), //'/marine/manual/data-log': (context) => marineManualDataStatusLog.MarineManualDataStatusLog(), // This is handled in onGenerateRoute '/marine/manual/image-request': (context) => const marineManualImageRequest.MarineImageRequestScreen(), // 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/overview': (context) => marineInvestigativeOverview.OverviewScreen(), '/marine/investigative/entry': (context) => marineInvestigativeEntry.EntryScreen(), '/marine/investigative/report': (context) => marineInvestigativeReport.ReportScreen(), }, ); }, ); } } // --- END: MODIFIED RootApp --- 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 app data...', style: TextStyle(fontSize: 16)), ], ), ), ); } }