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.

This commit is contained in:
Nico
2025-06-04 22:19:58 +02:00
parent 4b88071700
commit ef5faf7d3d
2 changed files with 147 additions and 83 deletions

View File

@@ -458,96 +458,148 @@ class _ExcursionMainState extends State<ExcursionMain> {
), ),
]; ];
// Begin of widget tree return PopScope(
return Scaffold( canPop: false,
appBar: AppBar( onPopInvoked: (didPop) async {
title: Text(AppLocalizations.of(context)!.excursion), if (didPop) {
actions: [ return;
// Text(TrackingService().isTracking ? "Tracking" : "Not tracking") }
Image.asset(
TrackingService().isTracking ? "assets/icons/tracking_on.png" : "assets/icons/tracking_off.png", // Show confirmation dialog
width: 40, final result = await showDialog<int>(
), context: context,
], builder: (context) => AlertDialog(
), title: const Text('Seite verlassen?'),
body: PageTransitionSwitcher( content: const Text('Möchten Sie die Seite wirklich verlassen?'),
duration: const Duration(microseconds: 800), actions: [
transitionBuilder: ( TextButton(
Widget child, onPressed: () => Navigator.of(context).pop(0),
Animation<double> animation, child: const Text('Nein'),
Animation<double> secondaryAnimation, ),
) { TextButton(
return SharedAxisTransition( onPressed: () => Navigator.of(context).pop(1),
animation: animation, child: const Text('Ja und Template speichern'),
secondaryAnimation: secondaryAnimation, ),
transitionType: SharedAxisTransitionType.vertical, TextButton(
child: child, onPressed: () => Navigator.of(context).pop(2),
); child: const Text('Ja ohne Template'),
}, ),
child: Stepper( ],
key: ValueKey<int>(currentStep), ),
steps: getSteps(), );
currentStep: currentStep,
onStepTapped: (value) { if (result == null || result == 0) {
setState(() { return;
currentStep = value; } 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<double> animation,
Animation<double> secondaryAnimation,
) {
return SharedAxisTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.vertical,
child: child,
);
}, },
onStepContinue: () async { child: Stepper(
final isLastStep = currentStep == getSteps().length - 1; key: ValueKey<int>(currentStep),
steps: getSteps(),
if (!isLastStep) { currentStep: currentStep,
var res = await saveTemplate( onStepTapped: (value) {
getFieldsText(),
DatabasesEnum.excursion,
);
isTemplate = true;
setState(() { setState(() {
rmap["ID"]!["controller"]!.text = res.toString(); currentStep = value;
currentStep += 1;
}); });
} else { },
if (widget.isSent) { onStepContinue: () async {
Navigator.pushNamedAndRemoveUntil( final isLastStep = currentStep == getSteps().length - 1;
context,
'/home',
(route) => false,
);
return;
}
bool empty = CheckRequired.checkRequired(rmap); if (!isLastStep) {
// for debugging always false var res = await saveTemplate(
// empty = false;
if (empty) {
AddEntriesDialogHelper.showTemplateDialog(
context,
getFieldsText(), getFieldsText(),
DatabasesEnum.excursion, DatabasesEnum.excursion,
); );
return;
isTemplate = true;
setState(() {
rmap["ID"]!["controller"]!.text = res.toString();
currentStep += 1;
});
} else { } else {
bool pop = await AddEntriesDialogHelper.showSaveOptionsDialog( if (widget.isSent) {
context, Navigator.pushNamedAndRemoveUntil(
getFieldsText(), context,
widget.isTemplate, '/home',
DatabasesEnum.excursion, (route) => false,
); );
if (pop && context.mounted) Navigator.of(context).pop(); 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: () {
onStepCancel: () { if (currentStep == 0) {
if (currentStep == 0) { Navigator.pop(context);
Navigator.pop(context); } else {
} else { setState(() {
setState(() { currentStep -= 1;
currentStep -= 1; });
}); }
} },
}, ),
), ),
), ),
); );

View File

@@ -9,10 +9,22 @@ import 'package:latlong2/latlong.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
class TrackingService { class TrackingService {
static final TrackingService _instance = TrackingService._internal(); static TrackingService? _instance;
factory TrackingService() => _instance;
factory TrackingService() {
_instance ??= TrackingService._internal();
return _instance!;
}
TrackingService._internal(); TrackingService._internal();
static void resetInstance() {
if (_instance != null) {
_instance!.dispose();
_instance = null;
}
}
List<LatLng> pathList = []; List<LatLng> pathList = [];
List<double> accuracyList = []; List<double> accuracyList = [];
Timer? _positionTimer; Timer? _positionTimer;