diff --git a/lib/app_state.dart b/lib/app_state.dart index 88b92bf..d90c69a 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -364,6 +364,7 @@ class AppState extends ChangeNotifier { /// Show re-authentication dialog if needed Future checkAndPromptReauthForMessages(BuildContext context) async { if (await needsReauthForMessages()) { + if (!context.mounted) return; _showReauthDialog(context); } } diff --git a/lib/migrations.dart b/lib/migrations.dart index 54f2dca..ec8e2fa 100644 --- a/lib/migrations.dart +++ b/lib/migrations.dart @@ -146,7 +146,7 @@ class OneTimeMigrations { debugPrint('[Migration] Stack trace: $stackTrace'); // Nuclear option: clear everything and show non-dismissible error dialog - if (context != null) { + if (context != null && context.mounted) { NuclearResetDialog.show(context, error, stackTrace); } else { // If no context available, just log and hope for the best diff --git a/lib/screens/coordinators/sheet_coordinator.dart b/lib/screens/coordinators/sheet_coordinator.dart index c984641..e8954c3 100644 --- a/lib/screens/coordinators/sheet_coordinator.dart +++ b/lib/screens/coordinators/sheet_coordinator.dart @@ -117,9 +117,8 @@ class SheetCoordinator { controller.closed.then((_) { _addSheetHeight = 0.0; onStateChanged(); - + // Handle dismissal by canceling session if still active - final appState = context.read(); if (appState.session != null) { debugPrint('[SheetCoordinator] AddNodeSheet dismissed - canceling session'); appState.cancelSession(); @@ -186,9 +185,8 @@ class SheetCoordinator { _editSheetHeight = 0.0; _transitioningToEdit = false; onStateChanged(); - + // Handle dismissal by canceling session if still active - final appState = context.read(); if (appState.editSession != null) { debugPrint('[SheetCoordinator] EditNodeSheet dismissed - canceling edit session'); appState.cancelEditSession(); diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index cc0514d..ff9702e 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -185,6 +185,7 @@ class _HomeScreenState extends State with TickerProviderStateMixin { // Run any needed migrations first final versionsNeedingMigration = await ChangelogService().getVersionsNeedingMigration(); + if (!mounted) return; for (final version in versionsNeedingMigration) { await ChangelogService().runMigration(version, appState, context); } @@ -209,6 +210,7 @@ class _HomeScreenState extends State with TickerProviderStateMixin { case PopupType.changelog: final changelogContent = await ChangelogService().getChangelogContentForDisplay(); + if (!mounted) return; if (changelogContent != null) { await showDialog( context: context, @@ -368,9 +370,11 @@ class _HomeScreenState extends State with TickerProviderStateMixin { ); // Reset height and clear selection when sheet is dismissed + final appState = context.read(); controller.closed.then((_) { + if (!mounted) return; _sheetCoordinator.resetTagSheetHeight(() => setState(() {})); - context.read().clearSuspectedLocationSelection(); + appState.clearSuspectedLocationSelection(); }); } diff --git a/lib/screens/settings/sections/node_profiles_section.dart b/lib/screens/settings/sections/node_profiles_section.dart index 26cb84f..ed997f0 100644 --- a/lib/screens/settings/sections/node_profiles_section.dart +++ b/lib/screens/settings/sections/node_profiles_section.dart @@ -118,7 +118,7 @@ class NodeProfilesSection extends StatelessWidget { ); // If user chose to create custom profile, open the profile editor - if (result == 'create') { + if (result == 'create' && context.mounted) { _createNewProfile(context); } // If user chose import from website, ProfileAddChoiceDialog handles opening the URL diff --git a/lib/widgets/add_node_sheet.dart b/lib/widgets/add_node_sheet.dart index 49bc90e..c836866 100644 --- a/lib/widgets/add_node_sheet.dart +++ b/lib/widgets/add_node_sheet.dart @@ -89,7 +89,8 @@ class _AddNodeSheetState extends State { void _checkSubmissionGuideAndProceed(BuildContext context, AppState appState, LocalizationService locService) async { // Check if user has seen the submission guide final hasSeenGuide = await ChangelogService().hasSeenSubmissionGuide(); - + if (!context.mounted) return; + if (!hasSeenGuide) { // Show submission guide dialog first final shouldProceed = await showDialog( @@ -97,13 +98,14 @@ class _AddNodeSheetState extends State { barrierDismissible: false, builder: (context) => const SubmissionGuideDialog(), ); - + if (!context.mounted) return; + // If user canceled the submission guide, don't proceed with submission if (shouldProceed != true) { return; } } - + // Now proceed with proximity check _checkProximityOnly(context, appState, locService); } diff --git a/lib/widgets/advanced_edit_options_sheet.dart b/lib/widgets/advanced_edit_options_sheet.dart index 7f82e27..ca4cfbc 100644 --- a/lib/widgets/advanced_edit_options_sheet.dart +++ b/lib/widgets/advanced_edit_options_sheet.dart @@ -185,6 +185,7 @@ class AdvancedEditOptionsSheet extends StatelessWidget { } // No custom scheme or app launch failed - redirect to app store + if (!context.mounted) return; await _redirectToAppStore(context, editor); } diff --git a/lib/widgets/download_area_dialog.dart b/lib/widgets/download_area_dialog.dart index 8ea1682..0adbdb2 100644 --- a/lib/widgets/download_area_dialog.dart +++ b/lib/widgets/download_area_dialog.dart @@ -264,8 +264,9 @@ class _DownloadAreaDialogState extends State { try { final id = DateTime.now().toIso8601String().replaceAll(':', '-'); final appDocDir = await OfflineAreaService().getOfflineAreaDir(); + if (!context.mounted) return; final dir = "${appDocDir.path}/$id"; - + // Get current tile provider info final appState = context.read(); final selectedProvider = appState.selectedTileProvider; @@ -292,6 +293,7 @@ class _DownloadAreaDialogState extends State { builder: (context) => const DownloadStartedDialog(), ); } catch (e) { + if (!context.mounted) return; Navigator.pop(context); showDialog( context: context, diff --git a/lib/widgets/edit_node_sheet.dart b/lib/widgets/edit_node_sheet.dart index c9c197e..0299dbc 100644 --- a/lib/widgets/edit_node_sheet.dart +++ b/lib/widgets/edit_node_sheet.dart @@ -92,7 +92,8 @@ class _EditNodeSheetState extends State { void _checkSubmissionGuideAndProceed(BuildContext context, AppState appState, LocalizationService locService) async { // Check if user has seen the submission guide final hasSeenGuide = await ChangelogService().hasSeenSubmissionGuide(); - + if (!context.mounted) return; + if (!hasSeenGuide) { // Show submission guide dialog first final shouldProceed = await showDialog( @@ -100,13 +101,14 @@ class _EditNodeSheetState extends State { barrierDismissible: false, builder: (context) => const SubmissionGuideDialog(), ); - + if (!context.mounted) return; + // If user canceled the submission guide, don't proceed with submission if (shouldProceed != true) { return; } } - + // Now proceed with proximity check _checkProximityOnly(context, appState, locService); } diff --git a/lib/widgets/nuclear_reset_dialog.dart b/lib/widgets/nuclear_reset_dialog.dart index e899f5c..b89d6fa 100644 --- a/lib/widgets/nuclear_reset_dialog.dart +++ b/lib/widgets/nuclear_reset_dialog.dart @@ -96,7 +96,8 @@ class NuclearResetDialog extends StatelessWidget { // Clear all app data await NuclearResetService.clearEverything(); - + + if (!context.mounted) return; // Show non-dismissible dialog await showDialog( context: context,