From 1656ffb00c2a461981ae7b76f23efae4c297ab3e Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 15 May 2024 19:59:10 +0200 Subject: [PATCH] server things --- lib/addCam/add_cam_main.dart | 250 ++++++++++++++++++++-------------- lib/home.dart | 2 +- lib/l10n/app_de.arb | 3 +- lib/l10n/app_en.arb | 5 + lib/methods/http_request.dart | 13 +- lib/other/db_helper.dart | 32 ++--- lib/viewCam/view_cams.dart | 40 ++++-- 7 files changed, 200 insertions(+), 145 deletions(-) diff --git a/lib/addCam/add_cam_main.dart b/lib/addCam/add_cam_main.dart index 4fb9c7c..e430bb1 100644 --- a/lib/addCam/add_cam_main.dart +++ b/lib/addCam/add_cam_main.dart @@ -15,13 +15,15 @@ import 'package:shared_preferences/shared_preferences.dart'; class AddCamMain extends StatefulWidget { final bool isTemplate; final bool isFinished; + final bool isSent; final Map? existingData; const AddCamMain( {super.key, this.isTemplate = false, this.existingData, - this.isFinished = false}); + this.isFinished = false, + this.isSent = false}); @override State createState() => _AddCamMainState(); @@ -121,9 +123,6 @@ class _AddCamMainState extends State { // determine live position with checks for denied permission and turned off location service Future _deteterminePosition() async { - - - bool locationEnabled; LocationPermission permissionGiven; @@ -182,10 +181,10 @@ class _AddCamMainState extends State { selectedPlatzung = widget.existingData!['Platzung'] ?? ""; kSchloNrC.text = widget.existingData!['KSchloNr'] ?? ""; datum = DateTime.parse(widget.existingData!['Datum']); - kontDat = widget.existingData!['KontDat'] == null + kontDat = widget.existingData!['KontDat'] == "" ? null : DateTime.parse(widget.existingData!['KontDat']); - abbauDat = widget.existingData!['AbbauDat'] == null + abbauDat = widget.existingData!['AbbauDat'] == "" ? null : DateTime.parse(widget.existingData!['AbbauDat']); auftragC.text = widget.existingData!['Auftrag'] ?? ""; @@ -235,114 +234,155 @@ class _AddCamMainState extends State { } Future _showServerErrorDialog() { + bool isLoading = false; + return showDialog( context: context, builder: (context) { - return AlertDialog( - title: Text(AppLocalizations.of(context)!.servererrortitle), - actions: [ - TextButton( - onPressed: () async { - int errorCode = _httpRequest(); + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return AlertDialog( + title: Text(AppLocalizations.of(context)!.servererrortitle), + content: isLoading + ? const SizedBox( + height: 100, + child: Center(child: CircularProgressIndicator())) + : null, + actions: [ + if (!isLoading) + TextButton( + onPressed: () async { + setState(() => isLoading = true); + int errorCode = await _httpRequest(); + setState(() => isLoading = false); - if (errorCode != 201) { - Navigator.pop(context); - _showServerErrorDialog(); - } - }, - child: Text(AppLocalizations.of(context)!.sendagain)), - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text(AppLocalizations.of(context)!.cancel)) - ], + if (errorCode != 201 && context.mounted) { + _showServerErrorDialog(); + } else { + if (context.mounted) Navigator.pop(context); + saveData(true); + _showSuccessDialog(); + } + }, + child: Text(AppLocalizations.of(context)!.sendagain)), + if (!isLoading) + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text(AppLocalizations.of(context)!.cancel)) + ], + ); + }, ); }); } Future showSaveOptionsDialog() async { + bool isLoading = false; + return showDialog( context: context, + barrierDismissible: + false, // Verhindert das Schließen des Dialogs durch den Benutzer builder: (BuildContext context) { - return AlertDialog( - title: Text(AppLocalizations.of(context)!.savemethod), - actions: [ - TextButton( - onPressed: () async { - saveTemplate(); - Navigator.pushNamedAndRemoveUntil( - context, - '/home', - (route) => false); - }, - child: Text(AppLocalizations.of(context)!.template)), - TextButton( - onPressed: () async { - int errorCode = _httpRequest(); + return StatefulBuilder( + builder: (context, setState) { + return AlertDialog( + title: isLoading + ? Text(AppLocalizations.of(context)!.loading) + : Text(AppLocalizations.of(context)!.savemethod), + content: isLoading + ? const SizedBox( + height: 100, + child: Center(child: CircularProgressIndicator())) + : null, + actions: [ + if (!isLoading) + TextButton( + onPressed: () async { + setState(() => isLoading = true); + saveTemplate(); + Navigator.pushNamedAndRemoveUntil( + context, '/home', (route) => false); + }, + child: Text(AppLocalizations.of(context)!.template)), + if (!isLoading) + TextButton( + onPressed: () async { + setState(() => isLoading = true); + int errorCode = await _httpRequest(); + setState(() => isLoading = false); - if (errorCode != 201) { - saveData(); - _showServerErrorDialog(); - } else { - saveData(); - return showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text( - AppLocalizations.of(context)!.successful), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text( - AppLocalizations.of(context)!.back)), - TextButton( - onPressed: () { - Navigator.pushNamedAndRemoveUntil( - context, '/home', (route) => false); - }, - child: Text(AppLocalizations.of(context)! - .continueB)) - ], - ); - }); - } - }, - child: Text(AppLocalizations.of(context)!.sendtoserver)), - TextButton( - onPressed: () async { - saveData(); - saveFile(); - }, - child: Text(AppLocalizations.of(context)!.saveasfile)), - TextButton( - onPressed: () { - saveData(); - Navigator.pushNamedAndRemoveUntil( - context, - '/home', - (route) => false); - }, - child: Text(AppLocalizations.of(context)!.justsave)), - TextButton( + if (errorCode != 201 || !context.mounted) { + saveData(); + _showServerErrorDialog(); + } else { + saveData(true); + _showSuccessDialog(); + } + }, + child: + Text(AppLocalizations.of(context)!.sendtoserver)), + if (!isLoading) + TextButton( + onPressed: () async { + setState(() => isLoading = true); + saveData(); + saveFile(); + setState(() => isLoading = false); + }, + child: Text(AppLocalizations.of(context)!.saveasfile)), + if (!isLoading) + TextButton( + onPressed: () { + saveData(); + Navigator.pushNamedAndRemoveUntil( + context, '/home', (route) => false); + }, + child: Text(AppLocalizations.of(context)!.justsave)), + if (!isLoading) + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text(AppLocalizations.of(context)!.cancel)), + ], + ); + }, + ); + }); + } + + Future _showSuccessDialog() async { + return showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(AppLocalizations.of(context)!.successful), + actions: [ +/* TextButton( onPressed: () { Navigator.pop(context); }, - child: Text(AppLocalizations.of(context)!.cancel)), + child: Text(AppLocalizations.of(context)!.back)), */ + TextButton( + onPressed: () { + Navigator.pushNamedAndRemoveUntil( + context, '/home', (route) => false); + }, + child: Text(AppLocalizations.of(context)!.continueB)) ], ); }); } - int _httpRequest() { + Future _httpRequest() async { Map place = getPlace(); - Methods method = Methods(); + HttpRequest method = HttpRequest(); - method.httpRequest(jsonEncode(place)); + await method.httpRequest(jsonEncode(place)); return method.errorCode; } @@ -366,21 +406,19 @@ class _AddCamMainState extends State { await file.writeAsString(jsonPlace); } catch (e) { if (mounted) { - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(AppLocalizations.of(context)!.savefilefailed))); } + Navigator.pop(context); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(AppLocalizations.of(context)!.savefilefailed))); + } return; } if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Datei gespeichert in $selectedDirectory'))); + SnackBar(content: Text('Datei gespeichert in $selectedDirectory'))); } if (mounted) { - Navigator.pushNamedAndRemoveUntil( - context, - '/home', - (route) => false); + Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false); } } @@ -432,12 +470,16 @@ class _AddCamMainState extends State { // If the user has filled all needed values this function will be called to safe them in the database // * also creates a json string to send it to the server later - void saveData() async { + void saveData([bool sent = false]) async { var placeDB = DBHelper(); - Map place = getPlace(); - await placeDB.addPlace(place); + // Get the ID of the newly added or updated place + int newPlaceId = await placeDB.addPlace(place); + + if (sent == true) { + placeDB.updateSent(newPlaceId); // Update 'Sent' using the correct ID + } if (widget.isTemplate) { await placeDB.deleteTemplate(cid.text); @@ -721,7 +763,7 @@ class _AddCamMainState extends State { onDateChanged: (value) { abbauDat = value; }, - ), + ), ], ), const SizedBox( @@ -832,7 +874,9 @@ class _AddCamMainState extends State { List emptyFields = validateData(); // ! always filled out empty = false; - if (empty == true) { + if (widget.isSent) { + Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false); + } else if (empty == true) { showTemplateDialog(emptyFields); return; } else if (empty == false) { diff --git a/lib/home.dart b/lib/home.dart index 1e372a3..9b08bfc 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -18,7 +18,7 @@ class HomePage extends StatelessWidget { File file = File(result.files.single.path!); String content = await file.readAsString(); - Methods().httpRequest(content); + HttpRequest().httpRequest(content); } } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9b3e37e..efe1024 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -97,5 +97,6 @@ "servererrortitle": "Serverfehler", "sendagain": "Nochmal senden", "successful": "Erfolgreich", - "back": "Zurück" + "back": "Zurück", + "loading": "Lädt" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fd9306e..01defac 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -472,6 +472,11 @@ "back": "Back", "@back": { "description": "back alert dialog option" + }, + + "loading": "Loading", + "@loading": { + "description": "just Loading" } } \ No newline at end of file diff --git a/lib/methods/http_request.dart b/lib/methods/http_request.dart index 1949dff..9560107 100644 --- a/lib/methods/http_request.dart +++ b/lib/methods/http_request.dart @@ -5,24 +5,23 @@ import 'package:dio/dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; -class Methods { +class HttpRequest { int? _errorCode; int get errorCode => _errorCode ?? 0; - Methods(); - - - - void httpRequest(String httpData) async { + Future httpRequest(String httpData) async { // print(jsonEncode(place)); final dio = Dio(); final SharedPreferences prefs = await SharedPreferences.getInstance(); - dio.options.responseType = ResponseType.plain; + dio.options + ..connectTimeout = const Duration(seconds: 5) + ..receiveTimeout = const Duration(seconds: 5) + ..responseType = ResponseType.plain; Response response = Response(requestOptions: RequestOptions(path: ''), statusCode: 400); try { diff --git a/lib/other/db_helper.dart b/lib/other/db_helper.dart index 824248b..d8a056e 100644 --- a/lib/other/db_helper.dart +++ b/lib/other/db_helper.dart @@ -35,50 +35,42 @@ class DBHelper { 'CREATE TABLE templates (ID INTEGER PRIMARY KEY AUTOINCREMENT, CID TEXT, Standort TEXT, Rudel TEXT, Datum DATE, Adresse1 TEXT, Adresse2 TEXT, Adresse3 TEXT, BLand TEXT, Lkr TEXT, BeiOrt TEXT, OrtInfo TEXT, Status TEXT, FFTyp TEXT, FotoFilm TEXT, MEZ TEXT, Platzung TEXT, KSchloNr TEXT, KontDat DATE, Betreuung TEXT, AbbauDat DATE, Auftrag TEXT, KontAbsp TEXT, SonstBem TEXT, FKontakt1 TEXT, FKontakt2 TEXT, FKontakt3 TEXT, KTage1 INTEGER, KTage2 INTEGER, ProtoAm DATE, IntKomm TEXT, DECLNG DECIMALS(4,8), DECLAT DECIMALS(4,8))'); } - // Function to add a finished entrie - Future addPlace(Map place) async { +// Function to add a finished entry and return its ID + Future addPlace(Map place) async { var placeDBClient = await placeDB; - - // gets an camid if it already exists final existingID = await placeDBClient.query( 'place', where: 'ID = ?', whereArgs: [place['ID']], ); - // checks if the camid var from before is empty to avoid double entries if (existingID.isNotEmpty) { updatePlace(place); - return; + return existingID.first['ID'] as int; // Return existing ID } - // inserts the entrie in the database - await placeDBClient.insert( + int id = await placeDBClient.insert( 'place', place, - - // replaces the entrie with the new onw if a unique value exists and conflicts - // conflictAlgorithm: ConflictAlgorithm.replace, + //conflictAlgorithm: ConflictAlgorithm.replace, ); + + return id; // Return the ID of the newly inserted entry } Future updatePlace(Map place) async { var placeDBClient = await placeDB; - await placeDBClient.update( - 'place', - place, - where: "ID = ?", - whereArgs: [place['ID']] - ); + await placeDBClient + .update('place', place, where: "ID = ?", whereArgs: [place['ID']]); } // function to update the sent value - Future updateSent() async { + Future updateSent(int id) async { var placeDBClient = await placeDB; - placeDBClient.update('place', true as Map, - where: 'ID = ?', whereArgs: ['ID']); + await placeDBClient.update('place', {'Sent': 1}, + where: 'ID = ?', whereArgs: [id]); } // same thing as before but with templatews diff --git a/lib/viewCam/view_cams.dart b/lib/viewCam/view_cams.dart index eed840d..01c6540 100644 --- a/lib/viewCam/view_cams.dart +++ b/lib/viewCam/view_cams.dart @@ -112,8 +112,12 @@ class _ViewCamsState extends State { appBar: AppBar( bottom: TabBar(tabs: [ Tab(text: AppLocalizations.of(context)!.completed), - Tab(text: AppLocalizations.of(context)!.uncompleted,), - Tab(text: AppLocalizations.of(context)!.map,), + Tab( + text: AppLocalizations.of(context)!.uncompleted, + ), + Tab( + text: AppLocalizations.of(context)!.map, + ), ]), title: Text(AppLocalizations.of(context)!.viewplacesappbar)), body: TabBarView( @@ -201,13 +205,14 @@ class _ViewCamsState extends State { onChanged: null, ), onTap: () async { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddCamMain( - isFinished: true, - existingData: place, - ))); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AddCamMain( + isSent: place['Sent'] == 1 ? true : false, + isFinished: true, + existingData: place, + ))); }, ), ); @@ -277,17 +282,26 @@ class _ViewCamsState extends State { return Marker( width: 80.0, height: 80.0, - point: LatLng(double.parse(e['DECLAT'].toString()), double.parse(e['DECLNG'].toString())), + point: LatLng(double.parse(e['DECLAT'].toString()), + double.parse(e['DECLNG'].toString())), child: Column( children: [ - const Icon(Icons.location_on, color: Colors.red,), - Text("ID: ${e['ID'].toString()}", style: const TextStyle(color: Colors.black),) + const Icon( + Icons.location_on, + color: Colors.red, + ), + Text( + "ID: ${e['ID'].toString()}", + style: const TextStyle(color: Colors.black), + ) ], )); }).toList(); return FlutterMap( options: MapOptions( - initialCenter: markers.isEmpty ? const LatLng(50, 10) : markers.first.point, + initialCenter: markers.isEmpty + ? const LatLng(50, 10) + : markers.first.point, interactionOptions: const InteractionOptions( flags: InteractiveFlag.pinchZoom | InteractiveFlag.drag |