import 'package:fforte/enums/databases.dart'; import 'package:fforte/screens/helper/add_entries_dialog_helper.dart'; import 'package:fforte/screens/helper/snack_bar_helper.dart'; import 'package:fforte/screens/addCam/exceptions/location_disabled_exception.dart'; import 'package:fforte/screens/addCam/exceptions/location_forbidden_exception.dart'; import 'package:fforte/screens/addCam/services/geolocator_service.dart'; import 'package:fforte/screens/sharedMethods/check_required.dart'; import 'package:fforte/screens/sharedMethods/save_template.dart'; import 'package:fforte/screens/sharedWidgets/datum.dart'; import 'package:fforte/screens/sharedWidgets/var_text_field.dart'; import 'package:flutter/material.dart'; import 'package:fforte/l10n/app_localizations.dart'; import 'package:geolocator/geolocator.dart'; import 'package:latlong2/latlong.dart'; import 'package:animations/animations.dart'; import 'widgets/abbau_dat.dart'; import 'widgets/karte.dart'; import 'widgets/kont_dat.dart'; import 'widgets/mez.dart'; import 'widgets/platzung.dart'; import 'widgets/status.dart'; class AddCamMain extends StatefulWidget { final bool isTemplate; final bool isSent; final Map? existingData; const AddCamMain({ super.key, this.isTemplate = false, this.existingData, this.isSent = false, }); @override State createState() => _AddCamMainState(); } class _AddCamMainState extends State { // var declaration int currentStep = 0; late bool isTemplate; String selectedStatus = 'aktiv'; String selectedFotoFilm = 'Foto'; String selectedMEZ = 'Sommerzeit'; String selectedPlatzung = ''; Position currentPosition = Position( longitude: 10.0, latitude: 51.0, timestamp: DateTime.now(), accuracy: 0.0, altitude: 0.0, heading: 0.0, speed: 0.0, speedAccuracy: 0.0, altitudeAccuracy: 0.0, headingAccuracy: 0.0, ); DateTime? abbauDat; DateTime datum = DateTime.now(); DateTime? kontDat = DateTime.now(); DateTime? protoAm = DateTime.now(); Map> rmap = { "ID": {"controller": TextEditingController(), "required": false}, // Step 1 "Standort": {"controller": TextEditingController(), "required": true}, "Status": {"controller": TextEditingController(), "required": true}, "Betreuung": {"controller": TextEditingController(), "required": false}, "CID": {"controller": TextEditingController(), "required": true}, "FFTyp": {"controller": TextEditingController(), "required": true}, "MEZ": {"controller": TextEditingController(), "required": true}, "KSchloNr": {"controller": TextEditingController(), "required": false}, "Rudel": {"controller": TextEditingController(), "required": true}, // Step 2 "DECLNG": {"controller": TextEditingController(), "required": false}, "DECLAT": {"controller": TextEditingController(), "required": false}, "BLand": {"controller": TextEditingController(), "required": true}, "Lkr": {"controller": TextEditingController(), "required": true}, "BeiOrt": {"controller": TextEditingController(), "required": true}, "OrtInfo": {"controller": TextEditingController(), "required": false}, "Platzung": {"controller": TextEditingController(), "required": true}, // Step 3 "Datum": {"controller": TextEditingController(), "required": false}, "KontDat": {"controller": TextEditingController(), "required": false}, "KTage1": {"controller": TextEditingController(), "required": true}, "KTage2": {"controller": TextEditingController(), "required": true}, "AbbauDat": {"controller": TextEditingController(), "required": false}, "Auftrag": {"controller": TextEditingController(), "required": false}, "KontAbsp": {"controller": TextEditingController(), "required": false}, "SonstBem": {"controller": TextEditingController(), "required": false}, // Step 4 "Adresse1": {"controller": TextEditingController(), "required": true}, "Adresse2": {"controller": TextEditingController(), "required": false}, "Adresse3": {"controller": TextEditingController(), "required": false}, "FKontakt1": {"controller": TextEditingController(), "required": false}, "FKontakt2": {"controller": TextEditingController(), "required": false}, "FKontakt3": {"controller": TextEditingController(), "required": false}, "IntKomm": {"controller": TextEditingController(), "required": false}, // Gone? "ProtoAm": {"controller": TextEditingController(), "required": false}, "FotoFilm": {"controller": TextEditingController(), "required": false}, "Sent": {"controller": TextEditingController(), "required": false}, }; Map getFieldsText() { Map puff = {}; for (var itemKey in rmap.keys) { puff[itemKey] = rmap[itemKey]!["controller"]!.text; } return puff; } @override void initState() { // updates the currentPosition var after the _determine position has finished. Means user view updates with his live location GeolocatorService.deteterminePosition() .then((result) => currentPosition = result) .catchError((error) { if (error is LocationDisabledException) { if (mounted) { SnackBarHelper.showSnackBarMessage( context, AppLocalizations.of(context)!.locationDisabled, ); } } else if (error is LocationForbiddenException) { if (mounted) { SnackBarHelper.showSnackBarMessage( context, AppLocalizations.of(context)!.locationForbidden, ); } } return currentPosition; }); // select initial werte rmap["MEZ"]!["controller"]!.text = selectedMEZ; rmap["Status"]!["controller"]!.text = selectedStatus; rmap["DECLAT"]!["controller"]!.text = currentPosition.latitude.toString(); rmap["DECLNG"]!["controller"]!.text = currentPosition.longitude.toString(); isTemplate = widget.isTemplate; // If a template is edited this fills in the existing values if (widget.existingData?.isNotEmpty ?? false) { for (var key in widget.existingData!.keys) { rmap[key]!["controller"]!.text = widget.existingData?[key].toString() ?? ""; } } super.initState(); } @override void dispose() { for (String key in rmap.keys) { rmap[key]!["controller"].dispose(); } super.dispose(); } // The widget tree which gets the shown widget from the ./cam_widgets.dart file // The names of the widgets should be self-explaining @override Widget build(BuildContext context) { // List with the steps. The steps itself will be "shown" later List getSteps() => [ // First step Step( title: Text(AppLocalizations.of(context)!.firststep), content: Column( children: [ Align( alignment: Alignment.bottomLeft, child: VarTextField( required: true, dbName: "Standort", textController: rmap["Standort"]!["controller"]!, // textController: betreuungC, localization: AppLocalizations.of(context)!.altstort, dbDesignation: DatabasesEnum.place, ), ), const SizedBox(height: 5), // -------------------- Align( alignment: Alignment.bottomLeft, child: Row( children: [ Text(AppLocalizations.of(context)!.status), const Text('*', style: TextStyle(color: Colors.red)), ], ), ), Status( initialStatus: selectedStatus, onStatusChanged: (status) { setState(() { rmap["Status"]!["controller"]!.text = status; }); }, ), // -------------------- VarTextField( textController: rmap["Betreuung"]!["controller"]!, localization: AppLocalizations.of(context)!.betreuung, dbName: "Betreuung", required: false, dbDesignation: DatabasesEnum.place, ), const SizedBox(height: 20), // -------------------- VarTextField( textController: rmap["CID"]!["controller"], localization: AppLocalizations.of(context)!.camLink, dbName: "CID", required: true, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["FFTyp"]!["controller"], localization: AppLocalizations.of(context)!.fftyp, dbName: "FFTyp", required: true, dbDesignation: DatabasesEnum.place, ), const SizedBox(height: 15), // -------------------- Align( alignment: Alignment.bottomLeft, child: Row( children: [ Text(AppLocalizations.of(context)!.zeiteinstellung), const Text('*', style: TextStyle(color: Colors.red)), ], ), ), MEZ( initialMEZ: selectedMEZ, onMEZChanged: (mez) { setState(() { selectedMEZ = mez; rmap["MEZ"]!["controller"]!.text = mez; }); }, ), const SizedBox(height: 15), // -------------------- VarTextField( textController: rmap["KSchloNr"]!["controller"], localization: AppLocalizations.of(context)!.kschlonr, dbName: "KSchloNr", required: false, dbDesignation: DatabasesEnum.place, ), const SizedBox(height: 5), // -------------------- VarTextField( textController: rmap["Rudel"]!["controller"], localization: AppLocalizations.of(context)!.rudel, dbName: "Rudel", required: true, dbDesignation: DatabasesEnum.place, ), const SizedBox(height: 15), ], ), ), // Second step Step( title: Text(AppLocalizations.of(context)!.secondstep), content: Column( children: [ Row( children: [ Column( children: [ Text(rmap["DECLAT"]!["controller"]!.text), Text(rmap["DECLNG"]!["controller"]!.text), ], ), const SizedBox(width: 15), ElevatedButton( onPressed: () async { final result = await Navigator.of(context).push( MaterialPageRoute( builder: (context) { return Karte( ortInfoC: rmap["OrtInfo"]!["controller"], beiOrtC: rmap["BeiOrt"]!["controller"], currentPosition: currentPosition, decLatC: rmap["DECLAT"]!["controller"], decLngC: rmap["DECLNG"]!["controller"], ); }, ), ); if (result != null) { setState(() { currentPosition = Position( latitude: result.latitude, longitude: result.longitude, timestamp: DateTime.now(), accuracy: 0.0, altitude: 0.0, altitudeAccuracy: 0.0, heading: 0.0, headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0, ); }); } }, child: Text(AppLocalizations.of(context)!.openMap), ), ], ), // -------------------- VarTextField( textController: rmap["BLand"]!["controller"]!, localization: AppLocalizations.of(context)!.bland, dbName: "BLand", required: true, dbDesignation: DatabasesEnum.place, defaultValue: "bLand", ), // -------------------- VarTextField( textController: rmap["Lkr"]!["controller"]!, localization: AppLocalizations.of(context)!.lkr, dbName: "Lkr", required: true, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["BeiOrt"]!["controller"]!, localization: AppLocalizations.of(context)!.beiort, dbName: "BeiOrt", required: true, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["OrtInfo"]!["controller"]!, localization: AppLocalizations.of(context)!.ortinfo, dbName: "OrtInfo", required: false, dbDesignation: DatabasesEnum.place, ), const SizedBox(height: 15), // -------------------- Align( alignment: Alignment.bottomLeft, child: Row( children: [ Text(AppLocalizations.of(context)!.platzung), const Text('*', style: TextStyle(color: Colors.red)), ], ), ), Platzung( initialPlatzung: selectedPlatzung, onPlatzungChanged: (platzung) { setState(() { selectedPlatzung = platzung; rmap["Platzung"]!["controller"]!.text = platzung; }); }, ), ], ), ), // Third step Step( title: Text(AppLocalizations.of(context)!.thirdstep), content: Column( children: [ Datum( initDatum: datum, onDateChanged: (value) { datum = value; rmap["Datum"]!["controller"]!.text = value.toString().split(" ").first; }, name: AppLocalizations.of(context)!.pickDate, ), // -------------------- KontDat( initKontDat: kontDat, onDateChanged: (value) { setState(() { kontDat = value; rmap["KontDat"]!["controller"]!.text = value.toString().split(" ").first; }); }, ), const SizedBox(height: 20), // -------------------- Align( alignment: Alignment.bottomLeft, child: Row( children: [ Text(AppLocalizations.of(context)!.ktage), const Text('*', style: TextStyle(color: Colors.red)), ], ), ), Row( children: [ Expanded(child: Text(AppLocalizations.of(context)!.ktage1)), const SizedBox(width: 15), Expanded( flex: 4, child: VarTextField( otherDefault: "24", textController: rmap["KTage1"]!["controller"]!, localization: AppLocalizations.of(context)!.ktage1, dbName: "KTage1", required: true, dbDesignation: DatabasesEnum.place, ), ), ], ), Row( children: [ Expanded(child: Text(AppLocalizations.of(context)!.ktage2)), const SizedBox(width: 15), Expanded( flex: 4, child: VarTextField( otherDefault: "48", textController: rmap["KTage2"]!["controller"]!, localization: AppLocalizations.of(context)!.ktage2, dbName: "KTage2", required: true, dbDesignation: DatabasesEnum.place, ), ), ], ), const SizedBox(height: 20), // -------------------- Row( children: [ AbbauDat( initAbbauDat: abbauDat, onDateChanged: (value) { abbauDat = value; rmap["AbbauDat"]!["controller"]!.text = value.toString().split(" ").first; }, ), ], ), const SizedBox(height: 20), // -------------------- VarTextField( textController: rmap["Auftrag"]!["controller"]!, localization: AppLocalizations.of(context)!.auftrag, dbName: "Auftrag", required: false, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["KontAbsp"]!["controller"]!, localization: AppLocalizations.of(context)!.kontabsp, dbName: "KontAbsp", required: false, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["SonstBem"]!["controller"]!, localization: AppLocalizations.of(context)!.sonstbemerkungen, dbName: "SonstBem", dbDesignation: DatabasesEnum.place, required: false, ), ], ), ), // Fourth step Step( title: Text(AppLocalizations.of(context)!.fourthstep), content: Column( children: [ VarTextField( textController: rmap["Adresse1"]!["controller"]!, localization: AppLocalizations.of(context)!.adresse1, dbName: "Adresse1", dbDesignation: DatabasesEnum.place, required: true, defaultValue: "addresse1", ), // -------------------- VarTextField( textController: rmap["Adresse2"]!["controller"]!, localization: AppLocalizations.of(context)!.adresse2, dbName: "Adresse2", required: false, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["Adresse3"]!["controller"]!, localization: AppLocalizations.of(context)!.adresse3, dbName: "Adresse3", required: false, dbDesignation: DatabasesEnum.place, ), const SizedBox(height: 15), // -------------------- VarTextField( textController: rmap["FKontakt1"]!["controller"]!, localization: AppLocalizations.of(context)!.fkontakt1, dbName: "FKontakt1", required: false, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["FKontakt2"]!["controller"]!, localization: AppLocalizations.of(context)!.fkontakt2, dbName: "FKontakt2", required: false, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["FKontakt3"]!["controller"]!, localization: AppLocalizations.of(context)!.fkontakt3, dbName: "FKontakt3", required: false, dbDesignation: DatabasesEnum.place, ), // -------------------- VarTextField( textController: rmap["IntKomm"]!["controller"]!, localization: AppLocalizations.of(context)!.intkomm, dbName: "IntKomm", required: false, dbDesignation: DatabasesEnum.place, ), ], ), ), ]; // Here the site is built with the steps from above return Scaffold( appBar: AppBar(title: Text(AppLocalizations.of(context)!.addplace)), body: PageTransitionSwitcher( duration: const Duration(milliseconds: 800), transitionBuilder: ( Widget child, Animation animation, Animation secondaryAnimation, ) { return SharedAxisTransition( animation: animation, secondaryAnimation: secondaryAnimation, transitionType: SharedAxisTransitionType.vertical, child: child, ); }, child: Stepper( key: ValueKey(currentStep), type: StepperType.vertical, steps: getSteps(), // Functions that handle the navigation through the steps currentStep: currentStep, onStepTapped: (value) { setState(() { currentStep = value; }); }, onStepContinue: () async { final isLastStep = currentStep == getSteps().length - 1; if (!isLastStep) { var res = await saveTemplate( getFieldsText(), DatabasesEnum.place, ); isTemplate = true; setState(() { rmap["ID"]!["controller"]!.text = res.toString(); currentStep += 1; }); } else { if (widget.isSent) { Navigator.pushNamedAndRemoveUntil( context, '/home', (route) => false, ); return; } bool empty = CheckRequired.checkRequired(rmap); // TODO for debugging always false empty = false; if (empty == true) { AddEntriesDialogHelper.showTemplateDialog( context, getFieldsText(), ); return; } else if (empty == false) { await AddEntriesDialogHelper.showSaveOptionsDialog( context, getFieldsText(), isTemplate, DatabasesEnum.place, ); } } }, onStepCancel: () { if (currentStep == 0) { Navigator.pop(context); } else { setState(() { currentStep -= 1; }); } }, ), ), ); } }