From ef5faf7d3dd3089be653cffd253be66b479a95e1 Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 4 Jun 2025 22:19:58 +0200 Subject: [PATCH] Refactor excursion_main.dart to implement a confirmation dialog on page exit, allowing users to save templates or exit without saving. Update TrackingService to support instance reset for better state management. --- lib/screens/excursion/excursion_main.dart | 214 ++++++++++++++-------- lib/services/tracking_service.dart | 16 +- 2 files changed, 147 insertions(+), 83 deletions(-) diff --git a/lib/screens/excursion/excursion_main.dart b/lib/screens/excursion/excursion_main.dart index 5d07111..8859a39 100644 --- a/lib/screens/excursion/excursion_main.dart +++ b/lib/screens/excursion/excursion_main.dart @@ -458,96 +458,148 @@ class _ExcursionMainState extends State { ), ]; - // Begin of widget tree - return Scaffold( - appBar: AppBar( - title: Text(AppLocalizations.of(context)!.excursion), - actions: [ - // Text(TrackingService().isTracking ? "Tracking" : "Not tracking") - Image.asset( - TrackingService().isTracking ? "assets/icons/tracking_on.png" : "assets/icons/tracking_off.png", - width: 40, - ), - ], - ), - body: PageTransitionSwitcher( - duration: const Duration(microseconds: 800), - transitionBuilder: ( - Widget child, - Animation animation, - Animation secondaryAnimation, - ) { - return SharedAxisTransition( - animation: animation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.vertical, - child: child, - ); - }, - child: Stepper( - key: ValueKey(currentStep), - steps: getSteps(), - currentStep: currentStep, - onStepTapped: (value) { - setState(() { - currentStep = value; - }); + return PopScope( + canPop: false, + onPopInvoked: (didPop) async { + if (didPop) { + return; + } + + // Show confirmation dialog + final result = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Seite verlassen?'), + content: const Text('Möchten Sie die Seite wirklich verlassen?'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(0), + child: const Text('Nein'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(1), + child: const Text('Ja und Template speichern'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(2), + child: const Text('Ja ohne Template'), + ), + ], + ), + ); + + if (result == null || result == 0) { + return; + } else if (result == 1) { + // Save as template and leave + if (context.mounted) { + saveTemplate( + getFieldsText(), + DatabasesEnum.excursion, + ); + } + TrackingService.resetInstance(); + if (context.mounted) { + Navigator.of(context).pop(); + } + } else { + // Just leave without saving + TrackingService.resetInstance(); + if (context.mounted) { + Navigator.of(context).pop(); + } + } + }, + child: Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context)!.excursion), + actions: [ + // Text(TrackingService().isTracking ? "Tracking" : "Not tracking") + Image.asset( + TrackingService().isTracking ? "assets/icons/tracking_on.png" : "assets/icons/tracking_off.png", + width: 40, + ), + ], + ), + body: PageTransitionSwitcher( + duration: const Duration(microseconds: 800), + transitionBuilder: ( + Widget child, + Animation animation, + Animation secondaryAnimation, + ) { + return SharedAxisTransition( + animation: animation, + secondaryAnimation: secondaryAnimation, + transitionType: SharedAxisTransitionType.vertical, + child: child, + ); }, - onStepContinue: () async { - final isLastStep = currentStep == getSteps().length - 1; - - if (!isLastStep) { - var res = await saveTemplate( - getFieldsText(), - DatabasesEnum.excursion, - ); - - isTemplate = true; + child: Stepper( + key: ValueKey(currentStep), + steps: getSteps(), + currentStep: currentStep, + onStepTapped: (value) { setState(() { - rmap["ID"]!["controller"]!.text = res.toString(); - currentStep += 1; + currentStep = value; }); - } else { - if (widget.isSent) { - Navigator.pushNamedAndRemoveUntil( - context, - '/home', - (route) => false, - ); - return; - } + }, + onStepContinue: () async { + final isLastStep = currentStep == getSteps().length - 1; - bool empty = CheckRequired.checkRequired(rmap); - // for debugging always false - // empty = false; - - if (empty) { - AddEntriesDialogHelper.showTemplateDialog( - context, + if (!isLastStep) { + var res = await saveTemplate( getFieldsText(), DatabasesEnum.excursion, ); - return; + + isTemplate = true; + setState(() { + rmap["ID"]!["controller"]!.text = res.toString(); + currentStep += 1; + }); } else { - bool pop = await AddEntriesDialogHelper.showSaveOptionsDialog( - context, - getFieldsText(), - widget.isTemplate, - DatabasesEnum.excursion, - ); - if (pop && context.mounted) Navigator.of(context).pop(); + if (widget.isSent) { + Navigator.pushNamedAndRemoveUntil( + context, + '/home', + (route) => false, + ); + return; + } + + bool empty = CheckRequired.checkRequired(rmap); + // for debugging always false + // empty = false; + + if (empty) { + AddEntriesDialogHelper.showTemplateDialog( + context, + getFieldsText(), + DatabasesEnum.excursion, + ); + return; + } else { + bool pop = await AddEntriesDialogHelper.showSaveOptionsDialog( + context, + getFieldsText(), + widget.isTemplate, + DatabasesEnum.excursion, + ); + if (pop && context.mounted) Navigator.of(context).pop(); + } } - } - }, - onStepCancel: () { - if (currentStep == 0) { - Navigator.pop(context); - } else { - setState(() { - currentStep -= 1; - }); - } - }, + }, + onStepCancel: () { + if (currentStep == 0) { + Navigator.pop(context); + } else { + setState(() { + currentStep -= 1; + }); + } + }, + ), ), ), ); diff --git a/lib/services/tracking_service.dart b/lib/services/tracking_service.dart index 75c11fe..de2c8f7 100644 --- a/lib/services/tracking_service.dart +++ b/lib/services/tracking_service.dart @@ -9,10 +9,22 @@ import 'package:latlong2/latlong.dart'; import 'package:shared_preferences/shared_preferences.dart'; class TrackingService { - static final TrackingService _instance = TrackingService._internal(); - factory TrackingService() => _instance; + static TrackingService? _instance; + + factory TrackingService() { + _instance ??= TrackingService._internal(); + return _instance!; + } + TrackingService._internal(); + static void resetInstance() { + if (_instance != null) { + _instance!.dispose(); + _instance = null; + } + } + List pathList = []; List accuracyList = []; Timer? _positionTimer;