environment_monitoring_app/lib/main.dart

594 lines
30 KiB
Dart

// 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/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;
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;
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;
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: <SingleChildWidget>[
ChangeNotifierProvider.value(value: authProvider),
Provider<ApiService>(create: (_) => apiService),
Provider<DatabaseHelper>(create: (_) => databaseHelper),
Provider<TelegramService>(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<TelegramService>(context, listen: false))),
Provider(
create: (context) =>
MarineManualPreDepartureService(Provider.of<ApiService>(context, listen: false))),
Provider(
create: (context) =>
MarineManualSondeCalibrationService(Provider.of<ApiService>(context, listen: false))),
Provider(
create: (context) =>
MarineManualEquipmentMaintenanceService(Provider.of<ApiService>(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<RootApp> createState() => _RootAppState();
}
class _RootAppState extends State<RootApp> {
// --- 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<AuthProvider>(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<ConnectivityResult> results) {
if (!results.contains(ConnectivityResult.none)) {
debugPrint("[Main] Internet connection detected.");
if (mounted) {
// Access services from provider context
final authProvider = Provider.of<AuthProvider>(context, listen: false);
final telegramService = Provider.of<TelegramService>(context, listen: false);
final retryService = Provider.of<RetryService>(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<AuthProvider>();
// 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<AuthProvider>(
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(),
'/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(),
// 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(),
'/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<SessionAwareWrapper> createState() => _SessionAwareWrapperState();
}
class _SessionAwareWrapperState extends State<SessionAwareWrapper> {
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<AuthProvider>(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<void> _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: <Widget>[
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)),
],
),
),
);
}
}