diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 63b97bb..fc93728 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ + const HomePage(), - '/addCamMain': (context) => const AddCamMain(), - '/viewCams': (context) => const ViewCams(), - '/introScreen': (context) => const IntroScreen(), - '/settings': (context) => const Settings(), - '/excursion': (context) => const ExcursionMain(), - }, - ); - } -} diff --git a/lib/home.dart b/lib/home.dart index dcd4ebf..9df1fdc 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,5 +1,5 @@ import 'dart:io'; -import 'package:fforte/methods/http_request.dart'; +import 'package:fforte/screens/sharedMethods/http_request.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; diff --git a/lib/interfaces/i_db.dart b/lib/interfaces/i_db.dart new file mode 100644 index 0000000..e113031 --- /dev/null +++ b/lib/interfaces/i_db.dart @@ -0,0 +1,32 @@ +import 'package:sqflite/sqflite.dart'; + +abstract interface class IDb { + Future get dB; + + initDatabases(); + + onCreateDatabases(Database excursionDB, int version); + + Future addMainEntry(Map excursion); + + Future updateMainEntry(Map excursion); + + Future updateSent(int id); + + Future addTemplate(Map templates); + + Future updateTemplate(Map template); + + Future>> getAllMainEntries(); + + Future>> getAllTemplates(); + + Future deleteAllMainEntries(); + + Future deleteAllTemplates(); + + Future deleteTemplateById(String id); + + Future deleteMainEntryById(String id); + +} diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 0c1958a..2fa845e 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -90,6 +90,7 @@ "pickfile": "Datei auswählen", "placedata": "Standortdaten", "sent": "Gesendet", + "fileSaved": "Datei gespeichtert bei: ", "savefilefailed": "Fehler. Bitte nochmal versuchen", "justplace": "Standort", "justsave": "Nur speichern", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 53b6407..074fafd 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -434,6 +434,11 @@ "description": "view data sent header" }, + "fileSaved": "File saved at: ", + "@fileSaved": { + "description": "file successfully saved" + }, + "savefilefailed": "Error. Please try again", "@savefilefailed": { "description": "save as file failed snackbar" diff --git a/lib/methods/excursion_db_helper.dart b/lib/methods/excursion_db_helper.dart index 6441562..7d5334e 100644 --- a/lib/methods/excursion_db_helper.dart +++ b/lib/methods/excursion_db_helper.dart @@ -1,3 +1,4 @@ +import 'package:fforte/interfaces/i_db.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; import 'dart:io' as io; @@ -6,29 +7,32 @@ import 'package:path/path.dart'; // * Gives the complete functionality for the databases // ! functions may not be named complete correctly -class ExcursionDBHelper { +class ExcursionDBHelper implements IDb{ static Database? _excursionDB; // checks if the databses are existing and creates them with the initPlaceDatabase function if not - Future get excursionDB async { + @override + Future get dB async { if (_excursionDB != null) { return _excursionDB!; } - _excursionDB = await initExcursionDatabase(); + _excursionDB = await initDatabases(); return _excursionDB!; } // Creates the databases with help from the _onCreateExcursion function - initExcursionDatabase() async { + @override + initDatabases() async { io.Directory documentsDirectory = await getApplicationCacheDirectory(); String path = join(documentsDirectory.path, 'excursionDB.db'); var excursionDB = - await openDatabase(path, version: 1, onCreate: _onCreateExcursion); + await openDatabase(path, version: 1, onCreate: onCreateDatabases); return excursionDB; } // The function that helps - _onCreateExcursion(Database excursionDB, int version) async { + @override + onCreateDatabases(Database excursionDB, int version) async { await excursionDB.execute( 'CREATE TABLE excursion (ID INTEGER PRIMARY KEY AUTOINCREMENT, Datum TEXT, Rudel TEXT, Teilnehmer TEXT, Jahr TEXT, Mjahr TEXT, Monat INTEGER, Saison TEXT, Dauer TEXT, BLjahr TEXT, BLand, TEXT, Lkr TEXT, BeiOrt TEXT, Wetter TEXT, Temperat TEXT, RegenVor TEXT, KmAuto TEXT, KmFuss TEXT, KmRad TEXT, KmTotal TEXT, KmAuProf TEXT, KmFuProz TEXT, KmRaProz TEXT, SpGut TEXT, SpSchlecht TEXT, SpurFund TEXT, SpurLang TEXT, SpurTiere Text, SpSicher TEXT, WelpenSp TEXT, WelpenAnz TEXT, WpSicher TEXT, LosungGes TEXT, LosunAnz TEXT, LosunGen TEXT, UrinAnz TEXT, UrinGen TEXT, OestrAnz TEXT, OestrGen TEXT, HaarAnz TEXT, HaarGen TEXT, LosungKm TEXT, GenetiKm TEXT, Hinweise TEXT, Bemerk TEXT, IntKomm TEXT, BimaNr TEXT, BimaName TEXT, BimaNutzer TEXT, BimaAGV TEXT, FallNum INTEGER, MHund TEXT, MLeine TEXT, LogDat TEXT, HinweiseSonstiges TEXT)'); await excursionDB.execute( @@ -36,8 +40,9 @@ class ExcursionDBHelper { } // Function to add a finished entry and return its ID - Future addExcursion(Map excursion) async { - var excursionDBClient = await excursionDB; + @override + Future addMainEntry(Map excursion) async { + var excursionDBClient = await dB; final existingID = await excursionDBClient.query( 'excursion', where: 'ID = ?', @@ -45,7 +50,7 @@ class ExcursionDBHelper { ); if (existingID.isNotEmpty) { - updateExcursion(excursion); + updateMainEntry(excursion); return existingID.first['ID'] as int; // Return existing ID } @@ -58,24 +63,27 @@ class ExcursionDBHelper { return id; // Return the ID of the newly inserted entry } - Future updateExcursion(Map excursion) async { - var excursionDBClient = await excursionDB; + @override + Future updateMainEntry(Map excursion) async { + var excursionDBClient = await dB; await excursionDBClient .update('excursion', excursion, where: "ID = ?", whereArgs: [excursion['ID']]); } // function to update the sent value + @override Future updateSent(int id) async { - var excursionDBClient = await excursionDB; + var excursionDBClient = await dB; await excursionDBClient.update('excursion', {'Sent': 1}, where: 'ID = ?', whereArgs: [id]); } // same thing as before but with templatews + @override Future addTemplate(Map templates) async { - var excursionDBClient = await excursionDB; + var excursionDBClient = await dB; final existingCID = await excursionDBClient.query( 'excursionTemplates', @@ -94,8 +102,9 @@ class ExcursionDBHelper { } // Updates a existing template + @override Future updateTemplate(Map template) async { - var excursionDBClient = await excursionDB; + var excursionDBClient = await dB; await excursionDBClient.update( 'excursionTemplates', @@ -106,32 +115,37 @@ class ExcursionDBHelper { } // get the finished entries from db - Future>> getExcursionen() async { - var excursionDBClient = await excursionDB; + @override + Future>> getAllMainEntries() async { + var excursionDBClient = await dB; return await excursionDBClient.query('excursion'); } // get the finished templates from db - Future>> getTemplates() async { - var excursionDBClient = await excursionDB; + @override + Future>> getAllTemplates() async { + var excursionDBClient = await dB; return await excursionDBClient.query('excursionTemplates'); } // deletes all finished entries from the db LOCALLY - Future deleteAllExcursionen() async { - var excursionDBClient = await excursionDB; + @override + Future deleteAllMainEntries() async { + var excursionDBClient = await dB; await excursionDBClient.delete('excursion'); } // deletes all templates from the db LOCALLY + @override Future deleteAllTemplates() async { - var excursionDBClient = await excursionDB; + var excursionDBClient = await dB; await excursionDBClient.delete('excursionTemplates'); } // delete specific template - Future deleteTemplate(String id) async { - var excursionDBClient = await excursionDB; + @override + Future deleteTemplateById(String id) async { + var excursionDBClient = await dB; await excursionDBClient.delete( 'excursionTemplates', where: 'ID = ?', @@ -140,8 +154,9 @@ class ExcursionDBHelper { } // delete specific excursion - Future deleteExcursion(String id) async { - var excursionDBClient = await excursionDB; + @override + Future deleteMainEntryById(String id) async { + var excursionDBClient = await dB; await excursionDBClient.delete( 'excursion', where: 'ID = ?', diff --git a/lib/methods/place_db_helper.dart b/lib/methods/place_db_helper.dart index d41d439..7520113 100644 --- a/lib/methods/place_db_helper.dart +++ b/lib/methods/place_db_helper.dart @@ -1,3 +1,4 @@ +import 'package:fforte/interfaces/i_db.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; import 'dart:io' as io; @@ -6,40 +7,42 @@ import 'package:path/path.dart'; // * Gives the complete functionality for the databases // ! functions may not be named complete correctly -class PlaceDBHelper { - static Database? _placeDB; +class PlaceDBHelper implements IDb{ + static Database? _dB; // checks if the databses are existing and creates them with the initPlaceDatabase function if not - Future get placeDB async { - if (_placeDB != null) { - return _placeDB!; + @override + Future get dB async { + if (_dB != null) { + return _dB!; } - _placeDB = await initPlaceDatabase(); - return _placeDB!; + _dB = await initDatabases(); + return _dB!; } // Creates the databases with help from the _onCreatePlace function - initPlaceDatabase() async { + @override + initDatabases() async { io.Directory documentsDirectory = await getApplicationCacheDirectory(); String path = join(documentsDirectory.path, 'placeDB.db'); var placeDB = - await openDatabase(path, version: 1, onCreate: _onCreatePlace); + await openDatabase(path, version: 1, onCreate: onCreateDatabases); return placeDB; } // The function that helps - _onCreatePlace(Database placeDB, int version) async { + @override + onCreateDatabases(Database placeDB, int version) async { await placeDB.execute( 'CREATE TABLE place (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), Sent INTEGER DEFAULT 0)'); await placeDB.execute( 'CREATE TABLE placeTemplates (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))'); - await placeDB.execute( - 'CREATE TABLE excursion (ID INTEGER PRIMARY KEY AUTOINCREMENT, Datum TEXT, Rudel TEXT, Teilnehmer TEXT, Jahr TEXT, Mjahr TEXT, Monat INTEGER, Saison TEXT, Dauer TEXT, BLjahr TEXT, BLand, TEXT, Lkr TEXT, BeiOrt TEXT, Wetter TEXT, Temperat TEXT, RegenVor TEXT, KmAuto TEXT, KmFuss TEXT, KmRad TEXT, KmTotal TEXT, KmAuProf TEXT, KmFuProz TEXT, KmRaProz TEXT, SpGut TEXT, SpSchlecht TEXT, SpurFund TEXT, SpurLang TEXT, SpurTiere Text, SpSicher TEXT, WelpenSp TEXT, WelpenAnz TEXT, WpSicher TEXT, LosungGes TEXT, LosunAnz TEXT, LosunGen TEXT, UrinAnz TEXT, UrinGen TEXT, OestrAnz TEXT, OestrGen TEXT, HaarAnz TEXT, HaarGen TEXT, LosungKm TEXT, GenetiKm TEXT, Hinweise TEXT, Bemerk TEXT, IntKomm TEXT, BimaNr TEXT, BimaName TEXT, BimaNutzer TEXT, BimaAGV TEXT, FallNum INTEGER, MHund TEXT, MLeine TEXT, LogDat TEXT)'); } // Function to add a finished entry and return its ID - Future addPlace(Map place) async { - var placeDBClient = await placeDB; + @override + Future addMainEntry(Map place) async { + var placeDBClient = await dB; final existingID = await placeDBClient.query( 'place', where: 'ID = ?', @@ -47,7 +50,7 @@ class PlaceDBHelper { ); if (existingID.isNotEmpty) { - updatePlace(place); + updateMainEntry(place); return existingID.first['ID'] as int; // Return existing ID } @@ -60,24 +63,27 @@ class PlaceDBHelper { return id; // Return the ID of the newly inserted entry } - Future updatePlace(Map place) async { - var placeDBClient = await placeDB; + @override + Future updateMainEntry(Map place) async { + var placeDBClient = await dB; await placeDBClient .update('place', place, where: "ID = ?", whereArgs: [place['ID']]); } // function to update the sent value + @override Future updateSent(int id) async { - var placeDBClient = await placeDB; + var placeDBClient = await dB; await placeDBClient.update('place', {'Sent': 1}, where: 'ID = ?', whereArgs: [id]); } // same thing as before but with templatews + @override Future addTemplate(Map templates) async { - var placeDBClient = await placeDB; + var placeDBClient = await dB; final existingCID = await placeDBClient.query( 'placeTemplates', @@ -96,8 +102,9 @@ class PlaceDBHelper { } // Updates a existing template + @override Future updateTemplate(Map template) async { - var placeDBClient = await placeDB; + var placeDBClient = await dB; await placeDBClient.update( 'placeTemplates', @@ -108,32 +115,37 @@ class PlaceDBHelper { } // get the finished entries from db - Future>> getPlace() async { - var placeDBClient = await placeDB; + @override + Future>> getAllMainEntries() async { + var placeDBClient = await dB; return await placeDBClient.query('place'); } // get the finished templates from db - Future>> getTemplates() async { - var placeDBClient = await placeDB; + @override + Future>> getAllTemplates() async { + var placeDBClient = await dB; return await placeDBClient.query('placeTemplates'); } // deletes all finished entries from the db LOCALLY - Future deleteAllPlaces() async { - var placeDBClient = await placeDB; + @override + Future deleteAllMainEntries() async { + var placeDBClient = await dB; await placeDBClient.delete('place'); } // deletes all templates from the db LOCALLY + @override Future deleteAllTemplates() async { - var placeDBClient = await placeDB; + var placeDBClient = await dB; await placeDBClient.delete('placeTemplates'); } // delete specific template - Future deleteTemplate(String id) async { - var placeDBClient = await placeDB; + @override + Future deleteTemplateById(String id) async { + var placeDBClient = await dB; await placeDBClient.delete( 'placeTemplates', where: 'ID = ?', @@ -142,8 +154,9 @@ class PlaceDBHelper { } // delete specific place - Future deletePlace(String id) async { - var placeDBClient = await placeDB; + @override + Future deleteMainEntryById(String id) async { + var placeDBClient = await dB; await placeDBClient.delete( 'place', where: 'ID = ?', diff --git a/lib/screens/Excursion/excursion_main.dart b/lib/screens/Excursion/excursion_main.dart index 7d22d3e..1b3ab0d 100644 --- a/lib/screens/Excursion/excursion_main.dart +++ b/lib/screens/Excursion/excursion_main.dart @@ -22,7 +22,7 @@ class ExcursionMain extends StatefulWidget { class _ExcursionMainState extends State { // all TextEditingController because its easier - Map getTextFields() { + Map getFieldsController() { Map rmap = { // Step 1 "LogDat": TextEditingController(), @@ -99,7 +99,7 @@ class _ExcursionMainState extends State { Datum( initDatum: DateTime.now(), onDateChanged: (date) { - getTextFields()["LogDat"]!.text = date.toString(); + getFieldsController()["LogDat"]!.text = date.toString(); }, name: AppLocalizations.of(context)!.date, ), @@ -108,7 +108,7 @@ class _ExcursionMainState extends State { ), // ---------- Pack VarTextField( - textController: getTextFields()["Rudel"]!, + textController: getFieldsController()["Rudel"]!, localization: AppLocalizations.of(context)!.rudel, dbName: "Rudel", required: false, @@ -119,7 +119,7 @@ class _ExcursionMainState extends State { ), // ---------- Participants VarTextField( - textController: getTextFields()["Teilnehm"]!, + textController: getFieldsController()["Teilnehm"]!, localization: AppLocalizations.of(context)!.teilnehmer, dbName: "Teilnehm", required: false, @@ -130,7 +130,7 @@ class _ExcursionMainState extends State { ), // ---------- Duration VarTextField( - textController: getTextFields()["Dauer"]!, + textController: getFieldsController()["Dauer"]!, localization: AppLocalizations.of(context)!.dauer, dbName: "Dauer", required: false, @@ -141,15 +141,15 @@ class _ExcursionMainState extends State { ), // ---------- Dog(leash) HundULeine(onMHundChanged: (mHund, mLeine) { - getTextFields()["MHund"]!.text = mHund; - getTextFields()["MLeine"]!.text = mLeine; + getFieldsController()["MHund"]!.text = mHund; + getFieldsController()["MLeine"]!.text = mLeine; }), const SizedBox( height: 10, ), // ---------- State VarTextField( - textController: getTextFields()["BLand"]!, + textController: getFieldsController()["BLand"]!, localization: AppLocalizations.of(context)!.bland, dbName: "BLand", required: false, @@ -160,7 +160,7 @@ class _ExcursionMainState extends State { ), // ---------- Country VarTextField( - textController: getTextFields()["Lkr"]!, + textController: getFieldsController()["Lkr"]!, localization: AppLocalizations.of(context)!.lkr, dbName: "Lkr", required: false, @@ -171,7 +171,7 @@ class _ExcursionMainState extends State { ), // ---------- By State VarTextField( - textController: getTextFields()["BeiOrt"]!, + textController: getFieldsController()["BeiOrt"]!, localization: AppLocalizations.of(context)!.beiort, dbName: "BeiOrt", required: false, @@ -186,7 +186,7 @@ class _ExcursionMainState extends State { height: 10, ), VarTextField( - textController: getTextFields()["BimaNr"]!, + textController: getFieldsController()["BimaNr"]!, localization: AppLocalizations.of(context)!.bimaNr, dbName: "BimaNr", required: false, @@ -197,7 +197,7 @@ class _ExcursionMainState extends State { ), // ---------- Bima name VarTextField( - textController: getTextFields()["BimaName"]!, + textController: getFieldsController()["BimaName"]!, localization: AppLocalizations.of(context)!.bimaName, dbName: "BimaName", required: false, @@ -209,7 +209,7 @@ class _ExcursionMainState extends State { // ---------- Bima user BimaNutzer(onBimaNutzerChanged: (value) { setState(() { - getTextFields()["BimaNutzer"]!.text = value; + getFieldsController()["BimaNutzer"]!.text = value; }); }), const SizedBox( @@ -217,7 +217,7 @@ class _ExcursionMainState extends State { ), // ---------- Bima AGV VarTextField( - textController: getTextFields()["BimaAGV"]!, + textController: getFieldsController()["BimaAGV"]!, localization: AppLocalizations.of(context)!.bimaAGV, dbName: "BimaAGV", required: false, @@ -231,7 +231,7 @@ class _ExcursionMainState extends State { children: [ // ---------- Weather VarTextField( - textController: getTextFields()["Wetter"]!, + textController: getFieldsController()["Wetter"]!, localization: AppLocalizations.of(context)!.wetter, dbName: "Wetter", required: false, @@ -240,7 +240,7 @@ class _ExcursionMainState extends State { const SizedBox(height: 10), // ---------- Temperature VarTextField( - textController: getTextFields()["Temperat"]!, + textController: getFieldsController()["Temperat"]!, localization: AppLocalizations.of(context)!.temperatur, dbName: "Temperat", required: false, @@ -248,16 +248,16 @@ class _ExcursionMainState extends State { ), const SizedBox(height: 10), // ---------- Last precipitation - LetzterNiederschlag(controller: getTextFields()["RegenVor"]!), + LetzterNiederschlag(controller: getFieldsController()["RegenVor"]!), const SizedBox(height: 20), // ---------- Track conditions StreckeUSpurbedingungen( - kmAutoController: getTextFields()["KmAuto"]!, - kmFussController: getTextFields()["KmFuss"]!, - kmRadController: getTextFields()["KmRad"]!, - spGutController: getTextFields()["SpGut"]!, - spMittelController: getTextFields()["SpMittel"]!, - spSchlechtController: getTextFields()["SpSchlecht"]!, + kmAutoController: getFieldsController()["KmAuto"]!, + kmFussController: getFieldsController()["KmFuss"]!, + kmRadController: getFieldsController()["KmRad"]!, + spGutController: getFieldsController()["SpGut"]!, + spMittelController: getFieldsController()["SpMittel"]!, + spSchlechtController: getFieldsController()["SpSchlecht"]!, ), const SizedBox( height: 20, @@ -265,27 +265,27 @@ class _ExcursionMainState extends State { const Divider(), // ---------- Track found SpurGefunden( - spurFund: getTextFields()["SpurFund"]!, - spurLang: getTextFields()["SpurLang"]!, - spurTiere: getTextFields()["SpurTiere"]!, - spSicher: getTextFields()["SpSicher"]!, - welpenSp: getTextFields()["WelpenSp"]!, - welpenAnz: getTextFields()["WelpenAnz"]!, - wpSicher: getTextFields()["WpSicher"]!), + spurFund: getFieldsController()["SpurFund"]!, + spurLang: getFieldsController()["SpurLang"]!, + spurTiere: getFieldsController()["SpurTiere"]!, + spSicher: getFieldsController()["SpSicher"]!, + welpenSp: getFieldsController()["WelpenSp"]!, + welpenAnz: getFieldsController()["WelpenAnz"]!, + wpSicher: getFieldsController()["WpSicher"]!), const SizedBox( height: 20, ), // ---------- Counts Anzahlen( - losungAnz: getTextFields()["LosungAnz"]!, - losungGes: getTextFields()["LosungGes"]!, - losungGen: getTextFields()["LosungGen"]!, - urinAnz: getTextFields()["UrinAnz"]!, - urinGen: getTextFields()["UrinGen"]!, - oestrAnz: getTextFields()["OestrAnz"]!, - oestrGen: getTextFields()["OestrGen"]!, - haarAnz: getTextFields()["HaarAnz"]!, - haarGen: getTextFields()["HaarGen"]!, + losungAnz: getFieldsController()["LosungAnz"]!, + losungGes: getFieldsController()["LosungGes"]!, + losungGen: getFieldsController()["LosungGen"]!, + urinAnz: getFieldsController()["UrinAnz"]!, + urinGen: getFieldsController()["UrinGen"]!, + oestrAnz: getFieldsController()["OestrAnz"]!, + oestrGen: getFieldsController()["OestrGen"]!, + haarAnz: getFieldsController()["HaarAnz"]!, + haarGen: getFieldsController()["HaarGen"]!, ), const SizedBox( height: 20, @@ -304,7 +304,7 @@ class _ExcursionMainState extends State { ), ), Hinweise( - hinweise: getTextFields()["Hinweise"]!, + hinweise: getFieldsController()["Hinweise"]!, ), ], ), @@ -315,7 +315,7 @@ class _ExcursionMainState extends State { children: [ // ---------- Remarks VarTextField( - textController: getTextFields()["Bemerk"]!, + textController: getFieldsController()["Bemerk"]!, localization: AppLocalizations.of(context)!.sonstbemerkungen, dbName: "Bemerk", required: false, @@ -326,7 +326,7 @@ class _ExcursionMainState extends State { ), // ---------- Internal communication VarTextField( - textController: getTextFields()["IntKomm"]!, + textController: getFieldsController()["IntKomm"]!, localization: AppLocalizations.of(context)!.intkomm, dbName: "IntKomm", required: false, diff --git a/lib/screens/addCam/add_cam_main.dart b/lib/screens/addCam/add_cam_main.dart index 6f9fe47..4a669e6 100644 --- a/lib/screens/addCam/add_cam_main.dart +++ b/lib/screens/addCam/add_cam_main.dart @@ -1,19 +1,21 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:fforte/enums/databases.dart'; import 'package:fforte/screens/addCam/cam_widgets.dart'; import 'package:fforte/methods/place_db_helper.dart'; -import 'package:fforte/methods/http_request.dart'; +import 'package:fforte/screens/sharedMethods/http_request.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/save_file.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:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:geolocator/geolocator.dart'; import 'package:latlong2/latlong.dart'; import 'package:animations/animations.dart'; -import 'package:shared_preferences/shared_preferences.dart'; class AddCamMain extends StatefulWidget { final bool isTemplate; @@ -22,11 +24,11 @@ class AddCamMain extends StatefulWidget { final Map? existingData; const AddCamMain( - {super.key, - this.isTemplate = false, - this.existingData, - this.isFinished = false, - this.isSent = false}); + {super.key, + this.isTemplate = false, + this.existingData, + this.isFinished = false, + this.isSent = false}); @override State createState() => _AddCamMainState(); @@ -66,16 +68,16 @@ class _AddCamMainState extends State { 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); + 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(); @@ -84,40 +86,40 @@ class _AddCamMainState extends State { Map getPlace() { Map place = { - 'ID': widget.existingData?['ID'], - 'CID': cid.text, - 'Rudel': rudelC.text, - 'Datum': datum.toString().split(" ").first, - 'Adresse1': adresse1C.text, - 'Adresse2': adresse2C.text, - 'Adresse3': adresse3C.text, - 'BLand': bLandC.text, - 'Lkr': lkrC.text, - 'BeiOrt': beiOrtC.text, - 'OrtInfo': ortInfoC.text, - 'Status': selectedStatus, - 'FFTyp': ffTypC.text, - 'FotoFilm': selectedFotoFilm, - 'MEZ': selectedMEZ, - 'Platzung': selectedPlatzung, - 'KSchloNr': kSchloNrC.text, - 'KontDat': kontDat.toString().split(" ").first, - 'AbbauDat': abbauDat.toString().split(" ").first.replaceAll("null", ""), - 'Auftrag': auftragC.text, - 'KontAbsp': kontAbspC.text, - 'SonstBem': sonstBemC.text, - 'FKontakt1': fKontakt1C.text, - 'FKontakt2': fKontakt2C.text, - 'FKontakt3': fKontakt3C.text, - 'Standort': standortC.text, - 'KTage1': kTage1C.text, - 'KTage2': kTage2C.text, - 'ProtoAm': protoAm.toString().split(" ").first, - 'IntKomm': intKommC.text, - 'Betreuung': betreuungC.text, - 'DECLNG': currentPosition.longitude, - 'DECLAT': currentPosition.latitude, - }; + 'ID': widget.existingData?['ID'], + 'CID': cid.text, + 'Rudel': rudelC.text, + 'Datum': datum.toString().split(" ").first, + 'Adresse1': adresse1C.text, + 'Adresse2': adresse2C.text, + 'Adresse3': adresse3C.text, + 'BLand': bLandC.text, + 'Lkr': lkrC.text, + 'BeiOrt': beiOrtC.text, + 'OrtInfo': ortInfoC.text, + 'Status': selectedStatus, + 'FFTyp': ffTypC.text, + 'FotoFilm': selectedFotoFilm, + 'MEZ': selectedMEZ, + 'Platzung': selectedPlatzung, + 'KSchloNr': kSchloNrC.text, + 'KontDat': kontDat.toString().split(" ").first, + 'AbbauDat': abbauDat.toString().split(" ").first.replaceAll("null", ""), + 'Auftrag': auftragC.text, + 'KontAbsp': kontAbspC.text, + 'SonstBem': sonstBemC.text, + 'FKontakt1': fKontakt1C.text, + 'FKontakt2': fKontakt2C.text, + 'FKontakt3': fKontakt3C.text, + 'Standort': standortC.text, + 'KTage1': kTage1C.text, + 'KTage2': kTage2C.text, + 'ProtoAm': protoAm.toString().split(" ").first, + 'IntKomm': intKommC.text, + 'Betreuung': betreuungC.text, + 'DECLNG': currentPosition.longitude, + 'DECLAT': currentPosition.latitude, + }; return place; } @@ -125,46 +127,49 @@ class _AddCamMainState extends State { bool empty = false; // determine live position with checks for denied permission and turned off location service - Future _deteterminePosition() async { - bool locationEnabled; - LocationPermission permissionGiven; - - locationEnabled = await Geolocator.isLocationServiceEnabled(); - if (!locationEnabled && mounted) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(AppLocalizations.of(context)!.locationDisabled))); - return currentPosition; - } - - permissionGiven = await Geolocator.checkPermission(); - if (permissionGiven == LocationPermission.denied) { - permissionGiven = await Geolocator.requestPermission(); - if (permissionGiven == LocationPermission.denied && mounted) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(AppLocalizations.of(context)!.locationForbidden))); - - return currentPosition; - } - } - - if (permissionGiven == LocationPermission.deniedForever && mounted) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(AppLocalizations.of(context)!.locationForbidden))); - return currentPosition; - } - return currentPosition = await Geolocator.getCurrentPosition(); - } + // Future _deteterminePosition() async { + // bool locationEnabled; + // LocationPermission permissionGiven; + // + // locationEnabled = await Geolocator.isLocationServiceEnabled(); + // if (!locationEnabled && mounted) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text(AppLocalizations.of(context)!.locationDisabled))); + // return currentPosition; + // } + // + // permissionGiven = await Geolocator.checkPermission(); + // if (permissionGiven == LocationPermission.denied) { + // permissionGiven = await Geolocator.requestPermission(); + // if (permissionGiven == LocationPermission.denied && mounted) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text(AppLocalizations.of(context)!.locationForbidden))); + // + // return currentPosition; + // } + // } + // + // if (permissionGiven == LocationPermission.deniedForever && mounted) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text(AppLocalizations.of(context)!.locationForbidden))); + // return currentPosition; + // } + // return currentPosition = await Geolocator.getCurrentPosition(); + // } @override void initState() { super.initState(); // updates the currentPosition var after the _determine position has finished. Means user view updates with his live location - _deteterminePosition().then((position) { - setState(() { - currentPosition = position; - }); - }); + try { + GeolocatorService.deteterminePosition() + .then((result) => currentPosition = result); + } on LocationDisabledException { + showSnackBarMessage(AppLocalizations.of(context)!.locationDisabled); + } on LocationForbiddenException { + showSnackBarMessage(AppLocalizations.of(context)!.locationForbidden); + } // If a template is edited this fills in the existing values if (widget.isTemplate || widget.isFinished && widget.existingData != null) { @@ -207,177 +212,184 @@ class _AddCamMainState extends State { } } + void showSnackBarMessage(String message) { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } + // Function to show the dialog where the user has to choose if he want to safe his values as a template Future showTemplateDialog(List emptyField) async { return showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return AlertDialog( - title: Text(AppLocalizations.of(context)!.fieldEmpty), - content: SingleChildScrollView( - child: ListBody(children: [Text(emptyField.join("; "))]), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text(AppLocalizations.of(context)!.cancel)), - TextButton( - onPressed: () { - saveTemplate(); - Navigator.pushNamedAndRemoveUntil( - context, '/home', (route) => false); - }, - child: Text(AppLocalizations.of(context)!.template)) - ], - ); - }); + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: Text(AppLocalizations.of(context)!.fieldEmpty), + content: SingleChildScrollView( + child: ListBody(children: [Text(emptyField.join("; "))]), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text(AppLocalizations.of(context)!.cancel)), + TextButton( + onPressed: () { + saveTemplate( + getPlace(), DatabasesEnum.place, widget.isTemplate); + Navigator.pushNamedAndRemoveUntil( + context, '/home', (route) => false); + }, + child: Text(AppLocalizations.of(context)!.template)) + ], + ); + }); } Future _showServerErrorDialog() { bool isLoading = false; return showDialog( - context: context, - builder: (context) { - 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); + context: context, + builder: (context) { + 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 && context.mounted) { + 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)) - ], - ); - }, - ); - }); + }, + 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 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); + context: context, + barrierDismissible: + false, // Verhindert das Schließen des Dialogs durch den Benutzer + builder: (BuildContext context) { + 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(getPlace(), DatabasesEnum.place, + widget.isTemplate); + 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 || !context.mounted) { + 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)), - ], - ); - }, - ); - }); + }, + 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( + 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)) - ], - ); - }); + TextButton( + onPressed: () { + Navigator.pushNamedAndRemoveUntil( + context, '/home', (route) => false); + }, + child: Text(AppLocalizations.of(context)!.continueB)) + ], + ); + }); } Future _httpRequest() async { @@ -390,67 +402,49 @@ child: Text(AppLocalizations.of(context)!.back)), */ return method.errorCode; } - Future saveFile() async { - String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); - SharedPreferences prefs = await SharedPreferences.getInstance(); - Map place = getPlace(); - String jsonPlace = jsonEncode(place); - - if (selectedDirectory == null) { - if (mounted) Navigator.pop(context); - return; - } - await prefs.setString('saveDir', selectedDirectory); - - File file = File( - '$selectedDirectory/${mounted ? AppLocalizations.of(context)!.justplace : const Text('')}-${standortC.text}.txt'); - + void _saveFile() { try { - await file.writeAsString(jsonPlace); - } catch (e) { - if (mounted) { - 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'))); - } - - if (mounted) { + saveFile( + getPlace(), AppLocalizations.of(context)!.justplace, standortC.text); + // TODO change to fileSaved + showSnackBarMessage(AppLocalizations.of(context)!.savefilefailed); Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false); + } catch (e) { + showSnackBarMessage(AppLocalizations.of(context)!.savefilefailed); } } // checks if required fields are not empty. If one is the name will be returned +// TODO rewrite List validateData() { List emptyFields = []; Map fields = { - AppLocalizations.of(context)!.camLink: cid, - AppLocalizations.of(context)!.rudel: rudelC, - AppLocalizations.of(context)!.adresse1: adresse1C, - AppLocalizations.of(context)!.bland: bLandC, - AppLocalizations.of(context)!.lkr: lkrC, - AppLocalizations.of(context)!.beiort: beiOrtC, - AppLocalizations.of(context)!.status: TextEditingController(text: selectedStatus), - AppLocalizations.of(context)!.fftyp: ffTypC, - "${AppLocalizations.of(context)!.foto} / ${AppLocalizations.of(context)!.filelocation}": TextEditingController(text: selectedFotoFilm), - AppLocalizations.of(context)!.zeiteinstellung: TextEditingController(text: selectedMEZ), - AppLocalizations.of(context)!.platzung: TextEditingController(text: selectedPlatzung), - AppLocalizations.of(context)!.ktage1: kTage1C, - AppLocalizations.of(context)!.ktage1: kTage2C, - AppLocalizations.of(context)!.location: standortC, - }; + AppLocalizations.of(context)!.camLink: cid, + AppLocalizations.of(context)!.rudel: rudelC, + AppLocalizations.of(context)!.adresse1: adresse1C, + AppLocalizations.of(context)!.bland: bLandC, + AppLocalizations.of(context)!.lkr: lkrC, + AppLocalizations.of(context)!.beiort: beiOrtC, + AppLocalizations.of(context)!.status: + TextEditingController(text: selectedStatus), + AppLocalizations.of(context)!.fftyp: ffTypC, + "${AppLocalizations.of(context)!.foto} / ${AppLocalizations.of(context)!.filelocation}": + TextEditingController(text: selectedFotoFilm), + AppLocalizations.of(context)!.zeiteinstellung: + TextEditingController(text: selectedMEZ), + AppLocalizations.of(context)!.platzung: + TextEditingController(text: selectedPlatzung), + AppLocalizations.of(context)!.ktage1: kTage1C, + AppLocalizations.of(context)!.ktage1: kTage2C, + AppLocalizations.of(context)!.location: standortC, + }; for (var entry in fields.entries) { - if (entry.value.text.isEmpty) { + if (entry.value.text.isEmpty) { emptyFields.add(entry.key); } - } + } empty = false; if (emptyFields.isNotEmpty) empty = true; @@ -460,18 +454,19 @@ child: Text(AppLocalizations.of(context)!.back)), */ // If the user decides to safe his values as a template this function is called to save the values in the database // If the user already edits a template this template will be upadted otherwise a new one will be created - void saveTemplate() async { - var placeDB = PlaceDBHelper(); - - Map templates = getPlace(); - - if (widget.isTemplate) { - await placeDB.updateTemplate(templates); - } else { - await placeDB.addTemplate(templates); - } - } + // void saveTemplate() async { + // var placeDB = PlaceDBHelper(); + // + // Map templates = getPlace(); + // + // if (widget.isTemplate) { + // await placeDB.updateTemplate(templates); + // } else { + // await placeDB.addTemplate(templates); + // } + // } + // TODO FINISHED HERE // 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([bool sent = false]) async { @@ -479,14 +474,14 @@ child: Text(AppLocalizations.of(context)!.back)), */ Map place = getPlace(); // Get the ID of the newly added or updated place - int newPlaceId = await placeDB.addPlace(place); + int newPlaceId = await placeDB.addMainEntry(place); if (sent == true) { placeDB.updateSent(newPlaceId); // Update 'Sent' using the correct ID } if (widget.isTemplate) { - await placeDB.deleteTemplate(cid.text); + await placeDB.deleteTemplateById(cid.text); } } @@ -496,148 +491,148 @@ child: Text(AppLocalizations.of(context)!.back)), */ 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: standortC, - localization: AppLocalizations.of(context)!.altstort, - dbDesignation: DatabasesEnum.place, - ), - ), - const SizedBox( - height: 5, - ), - Align( - alignment: Alignment.bottomLeft, - child: Row( + // First step + Step( + title: Text(AppLocalizations.of(context)!.firststep), + content: Column( children: [ - Text(AppLocalizations.of(context)!.status), - const Text( - '*', - style: TextStyle(color: Colors.red), + Align( + alignment: Alignment.bottomLeft, + child: VarTextField( + required: true, + dbName: "Standort", + textController: standortC, + 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(() { + selectedStatus = status; + }); + }, + ), + VarTextField( + textController: betreuungC, + localization: AppLocalizations.of(context)!.betreuung, + dbName: "Betreuung", + required: false, + dbDesignation: DatabasesEnum.place, + ), + const SizedBox( + height: 20, + ), + VarTextField( + textController: cid, + localization: AppLocalizations.of(context)!.camLink, + dbName: "CID", + required: true, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: ffTypC, + 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; + }); + }, + ), + const SizedBox( + height: 15, + ), + VarTextField( + textController: kSchloNrC, + localization: AppLocalizations.of(context)!.kschlonr, + dbName: "KSchloNr", + required: false, + dbDesignation: DatabasesEnum.place, + ), + const SizedBox( + height: 5, + ), + VarTextField( + textController: rudelC, + localization: AppLocalizations.of(context)!.rudel, + dbName: "Rudel", + required: true, + dbDesignation: DatabasesEnum.place, + ), + const SizedBox( + height: 15, ), ], )), - Status( - initialStatus: selectedStatus, - onStatusChanged: (status) { - setState(() { - selectedStatus = status; - }); - }, - ), - VarTextField( - textController: betreuungC, - localization: AppLocalizations.of(context)!.betreuung, - dbName: "Betreuung", - required: false, - dbDesignation: DatabasesEnum.place, - ), - const SizedBox( - height: 20, - ), - VarTextField( - textController: cid, - localization: AppLocalizations.of(context)!.camLink, - dbName: "CID", - required: true, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: ffTypC, - 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; - }); - }, - ), - const SizedBox( - height: 15, - ), - VarTextField( - textController: kSchloNrC, - localization: AppLocalizations.of(context)!.kschlonr, - dbName: "KSchloNr", - required: false, - dbDesignation: DatabasesEnum.place, - ), - const SizedBox( - height: 5, - ), - VarTextField( - textController: rudelC, - 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(currentPosition.latitude.toString()), - Text(currentPosition.longitude.toString()), - ], - ), - const SizedBox( - width: 15, - ), - ElevatedButton( - onPressed: () async { - final result = await Navigator.of(context) - .push( - MaterialPageRoute(builder: (context) { - return Karte( - ortInfoC: ortInfoC, - beiOrtC: beiOrtC, - currentPosition: currentPosition, - onPositionChange: (updatedPosition) { - setState(() { - currentPosition = updatedPosition; - }); - }, - ); - })); - if (result != null) { + // Second step + Step( + title: Text(AppLocalizations.of(context)!.secondstep), + content: Column( + children: [ + Row( + children: [ + Column( + children: [ + Text(currentPosition.latitude.toString()), + Text(currentPosition.longitude.toString()), + ], + ), + const SizedBox( + width: 15, + ), + ElevatedButton( + onPressed: () async { + final result = await Navigator.of(context) + .push( + MaterialPageRoute(builder: (context) { + return Karte( + ortInfoC: ortInfoC, + beiOrtC: beiOrtC, + currentPosition: currentPosition, + onPositionChange: (updatedPosition) { + setState(() { + currentPosition = updatedPosition; + }); + }, + ); + })); + if (result != null) { setState(() { currentPosition = Position( latitude: result.latitude, @@ -653,255 +648,269 @@ child: Text(AppLocalizations.of(context)!.back)), */ ); }); } - }, - child: Text(AppLocalizations.of(context)!.openMap)), - ], - ), - VarTextField( - textController: bLandC, - localization: AppLocalizations.of(context)!.bland, - dbName: "BLand", - required: true, - dbDesignation: DatabasesEnum.place, - defaultValue: "bLand", - ), - VarTextField( - textController: lkrC, - localization: AppLocalizations.of(context)!.lkr, - dbName: "Lkr", - required: true, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: beiOrtC, - localization: AppLocalizations.of(context)!.beiort, - dbName: "BeiOrt", - required: true, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: ortInfoC, - 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; - }); - }, - ), - ], - )), - // Third step - Step( - title: Text(AppLocalizations.of(context)!.thirdstep), - content: Column( - children: [ - Datum( - initDatum: datum, - onDateChanged: (value) { - datum = value; - }, - name: AppLocalizations.of(context)!.pickDate, - ), - KontDat( - initKontDat: kontDat, - onDateChanged: (value) { - setState(() { - kontDat = value; - }); - }, - ), - const SizedBox( - height: 20, - ), - Align( - alignment: Alignment.bottomLeft, - child: Row( - children: [ - Text(AppLocalizations.of(context)!.ktage), - const Text( - '*', - style: TextStyle(color: Colors.red), + }, + child: Text(AppLocalizations.of(context)!.openMap)), + ], + ), + VarTextField( + textController: bLandC, + localization: AppLocalizations.of(context)!.bland, + dbName: "BLand", + required: true, + dbDesignation: DatabasesEnum.place, + defaultValue: "bLand", + ), + VarTextField( + textController: lkrC, + localization: AppLocalizations.of(context)!.lkr, + dbName: "Lkr", + required: true, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: beiOrtC, + localization: AppLocalizations.of(context)!.beiort, + dbName: "BeiOrt", + required: true, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: ortInfoC, + 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; + }); + }, ), ], - ), - ), - - Row( - children: [ - Expanded( - child: Text( AppLocalizations.of(context)!.ktage1)), - - const SizedBox(width: 15,), - Expanded( - flex: 4, - child: VarTextField(otherDefault: "24", textController: kTage1C, 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: kTage2C, 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; - }, - ), - ], - ), - const SizedBox( - height: 20, - ), - VarTextField( - textController: auftragC, - localization: AppLocalizations.of(context)!.auftrag, - dbName: "Auftrag", - required: false, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: kontAbspC, - localization: AppLocalizations.of(context)!.kontabsp, - dbName: "KontAbsp", - required: false, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: sonstBemC, - 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: adresse1C, - localization: AppLocalizations.of(context)!.adresse1, - dbName: "Adresse1", - dbDesignation: DatabasesEnum.place, - required: true, - defaultValue: "addresse1", - ), - VarTextField( - textController: adresse2C, - localization: AppLocalizations.of(context)!.adresse2, - dbName: "Adresse2", - required: false, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: adresse3C, - localization: AppLocalizations.of(context)!.adresse3, - dbName: "Adresse2", - required: false, - dbDesignation: DatabasesEnum.place, - ), - const SizedBox( - height: 15, - ), - VarTextField( - textController: fKontakt1C, - localization: AppLocalizations.of(context)!.fkontakt1, - dbName: "FKontakt1", - required: false, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: fKontakt2C, - localization: AppLocalizations.of(context)!.fkontakt2, - dbName: "FKontakt2", - required: false, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: fKontakt3C, - localization: AppLocalizations.of(context)!.fkontakt3, - dbName: "FKontakt3", - required: false, - dbDesignation: DatabasesEnum.place, - ), - VarTextField( - textController: intKommC, - localization: AppLocalizations.of(context)!.intkomm, - dbName: "IntKomm", - required: false, - dbDesignation: DatabasesEnum.place, - ), - ], - )) - ]; + )), + // Third step + Step( + title: Text(AppLocalizations.of(context)!.thirdstep), + content: Column( + children: [ + Datum( + initDatum: datum, + onDateChanged: (value) { + datum = value; + }, + name: AppLocalizations.of(context)!.pickDate, + ), + KontDat( + initKontDat: kontDat, + onDateChanged: (value) { + setState(() { + kontDat = value; + }); + }, + ), + 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: kTage1C, + 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: kTage2C, + 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; + }, + ), + ], + ), + const SizedBox( + height: 20, + ), + VarTextField( + textController: auftragC, + localization: AppLocalizations.of(context)!.auftrag, + dbName: "Auftrag", + required: false, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: kontAbspC, + localization: AppLocalizations.of(context)!.kontabsp, + dbName: "KontAbsp", + required: false, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: sonstBemC, + 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: adresse1C, + localization: AppLocalizations.of(context)!.adresse1, + dbName: "Adresse1", + dbDesignation: DatabasesEnum.place, + required: true, + defaultValue: "addresse1", + ), + VarTextField( + textController: adresse2C, + localization: AppLocalizations.of(context)!.adresse2, + dbName: "Adresse2", + required: false, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: adresse3C, + localization: AppLocalizations.of(context)!.adresse3, + dbName: "Adresse2", + required: false, + dbDesignation: DatabasesEnum.place, + ), + const SizedBox( + height: 15, + ), + VarTextField( + textController: fKontakt1C, + localization: AppLocalizations.of(context)!.fkontakt1, + dbName: "FKontakt1", + required: false, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: fKontakt2C, + localization: AppLocalizations.of(context)!.fkontakt2, + dbName: "FKontakt2", + required: false, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: fKontakt3C, + localization: AppLocalizations.of(context)!.fkontakt3, + dbName: "FKontakt3", + required: false, + dbDesignation: DatabasesEnum.place, + ), + VarTextField( + textController: intKommC, + 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(), + 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; + // 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) { - saveTemplate(); + if (!isLastStep) { + saveTemplate( + getPlace(), DatabasesEnum.place, widget.isTemplate); setState(() { currentStep += 1; }); @@ -910,7 +919,8 @@ child: Text(AppLocalizations.of(context)!.back)), */ // ! always filled out // empty = false; if (widget.isSent) { - Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false); + Navigator.pushNamedAndRemoveUntil( + context, '/home', (route) => false); } else if (empty == true) { showTemplateDialog(emptyFields); return; @@ -918,15 +928,15 @@ child: Text(AppLocalizations.of(context)!.back)), */ await showSaveOptionsDialog(); } } - }, - onStepCancel: () { - if (currentStep == 0) { + }, + onStepCancel: () { + if (currentStep == 0) { Navigator.pop(context); } else { setState(() { currentStep -= 1; }); } - }))); + }))); } } diff --git a/lib/screens/addCam/add_cam_main.dart~ b/lib/screens/addCam/add_cam_main.dart~ deleted file mode 100644 index 7489eac..0000000 --- a/lib/screens/addCam/add_cam_main.dart~ +++ /dev/null @@ -1,892 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:fforte/addCam/cam_widgets.dart'; -import 'package:fforte/other/db_helper.dart'; -import 'package:fforte/methods/http_request.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:latlong2/latlong.dart'; -import 'package:animations/animations.dart'; -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.isSent = false}); - - @override - State createState() => _AddCamMainState(); -} - -class _AddCamMainState extends State { - // var declaration - int currentStep = 0; - // bool isTemplate = false; - - TextEditingController cid = TextEditingController(); - TextEditingController rudelC = TextEditingController(); - TextEditingController adresse1C = TextEditingController(); - TextEditingController adresse2C = TextEditingController(); - TextEditingController adresse3C = TextEditingController(); - TextEditingController bLandC = TextEditingController(); - TextEditingController lkrC = TextEditingController(); - TextEditingController beiOrtC = TextEditingController(); - TextEditingController ortInfoC = TextEditingController(); - TextEditingController ffTypC = TextEditingController(); - TextEditingController kSchloNrC = TextEditingController(); - TextEditingController auftragC = TextEditingController(); - TextEditingController kontAbspC = TextEditingController(); - TextEditingController sonstBemC = TextEditingController(); - TextEditingController fKontakt1C = TextEditingController(); - TextEditingController fKontakt2C = TextEditingController(); - TextEditingController fKontakt3C = TextEditingController(); - TextEditingController standortC = TextEditingController(); - TextEditingController kTage1C = TextEditingController(); - TextEditingController kTage2C = TextEditingController(); - TextEditingController intKommC = TextEditingController(); - TextEditingController betreuungC = TextEditingController(); - - 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 getPlace() { - Map place = { - 'ID': widget.existingData?['ID'], - 'CID': cid.text, - 'Rudel': rudelC.text, - 'Datum': datum.toString().split(" ").first, - 'Adresse1': adresse1C.text, - 'Adresse2': adresse2C.text, - 'Adresse3': adresse3C.text, - 'BLand': bLandC.text, - 'Lkr': lkrC.text, - 'BeiOrt': beiOrtC.text, - 'OrtInfo': ortInfoC.text, - 'Status': selectedStatus, - 'FFTyp': ffTypC.text, - 'FotoFilm': selectedFotoFilm, - 'MEZ': selectedMEZ, - 'Platzung': selectedPlatzung, - 'KSchloNr': kSchloNrC.text, - 'KontDat': kontDat.toString().split(" ").first, - 'AbbauDat': abbauDat.toString().split(" ").first.replaceAll("null", ""), - 'Auftrag': auftragC.text, - 'KontAbsp': kontAbspC.text, - 'SonstBem': sonstBemC.text, - 'FKontakt1': fKontakt1C.text, - 'FKontakt2': fKontakt2C.text, - 'FKontakt3': fKontakt3C.text, - 'Standort': standortC.text, - 'KTage1': kTage1C.text, - 'KTage2': kTage2C.text, - 'ProtoAm': protoAm.toString().split(" ").first, - 'IntKomm': intKommC.text, - 'Betreuung': betreuungC.text, - 'DECLNG': currentPosition.longitude, - 'DECLAT': currentPosition.latitude, - }; - - return place; - } - - bool empty = false; - - // determine live position with checks for denied permission and turned off location service - Future _deteterminePosition() async { - bool locationEnabled; - LocationPermission permissionGiven; - - locationEnabled = await Geolocator.isLocationServiceEnabled(); - if (!locationEnabled && mounted) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(AppLocalizations.of(context)!.locationDisabled))); - return currentPosition; - } - - permissionGiven = await Geolocator.checkPermission(); - if (permissionGiven == LocationPermission.denied) { - permissionGiven = await Geolocator.requestPermission(); - if (permissionGiven == LocationPermission.denied && mounted) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(AppLocalizations.of(context)!.locationForbidden))); - - return currentPosition; - } - } - - if (permissionGiven == LocationPermission.deniedForever && mounted) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(AppLocalizations.of(context)!.locationForbidden))); - return currentPosition; - } - return currentPosition = await Geolocator.getCurrentPosition(); - } - - @override - void initState() { - super.initState(); - - // updates the currentPosition var after the _determine position has finished. Means user view updates with his live location - _deteterminePosition().then((position) { - setState(() { - currentPosition = position; - }); - }); - - // If a template is edited this fills in the existing values - if (widget.isTemplate || widget.isFinished && widget.existingData != null) { - cid.text = widget.existingData!['CID'] ?? ""; - rudelC.text = widget.existingData!['Rudel'] ?? ""; - adresse1C.text = widget.existingData!['Adresse1'] ?? ""; - adresse2C.text = widget.existingData!['Adresse2'] ?? ""; - adresse3C.text = widget.existingData!['Adresse3'] ?? ""; - bLandC.text = widget.existingData!['BLand'] ?? ""; - lkrC.text = widget.existingData!['Lkr'] ?? ""; - beiOrtC.text = widget.existingData!['BeiOrt'] ?? ""; - ortInfoC.text = widget.existingData!['OrtInfo'] ?? ""; - selectedStatus = widget.existingData!['Status'] ?? ""; - ffTypC.text = widget.existingData!['FFTyp'] ?? ""; - selectedFotoFilm = widget.existingData!['FotoFilm'] ?? ""; - selectedMEZ = widget.existingData!['MEZ'] ?? ""; - selectedPlatzung = widget.existingData!['Platzung'] ?? ""; - kSchloNrC.text = widget.existingData!['KSchloNr'] ?? ""; - datum = DateTime.parse(widget.existingData!['Datum']); - kontDat = widget.existingData!['KontDat'] == "" - ? null - : DateTime.parse(widget.existingData!['KontDat']); - abbauDat = widget.existingData!['AbbauDat'] == "" - ? null - : DateTime.parse(widget.existingData!['AbbauDat']); - auftragC.text = widget.existingData!['Auftrag'] ?? ""; - kontAbspC.text = widget.existingData!['KontAbsp'] ?? ""; - sonstBemC.text = widget.existingData!['SonstBem'] ?? ""; - fKontakt1C.text = widget.existingData!['FKontakt1'] ?? ""; - fKontakt2C.text = widget.existingData!['FKontakt2'] ?? ""; - fKontakt3C.text = widget.existingData!['FKontakt3'] ?? ""; - standortC.text = widget.existingData!['Standort'] ?? ""; - kTage1C.text = widget.existingData!['KTage1'].toString(); - kTage2C.text = widget.existingData!['KTage2'].toString(); - protoAm = widget.existingData!['ProtoAm'] == null - ? null - : DateTime.parse(widget.existingData!['ProtoAm']); - intKommC.text = widget.existingData!['IntKomm'] ?? ""; - betreuungC.text = widget.existingData!['Betreuung'] ?? ""; - } - } - - // Function to show the dialog where the user has to choose if he want to safe his values as a template - Future showTemplateDialog(List emptyField) async { - return showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return AlertDialog( - title: Text(AppLocalizations.of(context)!.fieldEmpty), - content: SingleChildScrollView( - child: ListBody(children: [Text(emptyField.join("; "))]), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text(AppLocalizations.of(context)!.cancel)), - TextButton( - onPressed: () { - saveTemplate(); - Navigator.pushNamedAndRemoveUntil( - context, '/home', (route) => false); - }, - child: Text(AppLocalizations.of(context)!.template)) - ], - ); - }); - } - - Future _showServerErrorDialog() { - bool isLoading = false; - - return showDialog( - context: context, - builder: (context) { - 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 && 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 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 || !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)!.back)), */ - TextButton( - onPressed: () { - Navigator.pushNamedAndRemoveUntil( - context, '/home', (route) => false); - }, - child: Text(AppLocalizations.of(context)!.continueB)) - ], - ); - }); - } - - Future _httpRequest() async { - Map place = getPlace(); - - HttpRequest method = HttpRequest(); - - await method.httpRequest(jsonEncode(place)); - - return method.errorCode; - } - - Future saveFile() async { - String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); - SharedPreferences prefs = await SharedPreferences.getInstance(); - Map place = getPlace(); - String jsonPlace = jsonEncode(place); - - if (selectedDirectory == null) { - if (mounted) Navigator.pop(context); - return; - } - await prefs.setString('saveDir', selectedDirectory); - - File file = File( - '$selectedDirectory/${mounted ? AppLocalizations.of(context)!.justplace : const Text('')}-${standortC.text}.txt'); - - try { - await file.writeAsString(jsonPlace); - } catch (e) { - if (mounted) { - 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'))); - } - - if (mounted) { - Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false); - } - } - - // checks if required fields are not empty. If one is the name will be returned - List validateData() { - List emptyFields = []; - - Map fields = { - AppLocalizations.of(context)!.camLink: cid, - AppLocalizations.of(context)!.rudel: rudelC, - AppLocalizations.of(context)!.adresse1: adresse1C, - AppLocalizations.of(context)!.bland: bLandC, - AppLocalizations.of(context)!.lkr: lkrC, - AppLocalizations.of(context)!.beiort: beiOrtC, - AppLocalizations.of(context)!.status: TextEditingController(text: selectedStatus), - AppLocalizations.of(context)!.fftyp: ffTypC, - "${AppLocalizations.of(context)!.foto} / ${AppLocalizations.of(context)!.filelocation}": TextEditingController(text: selectedFotoFilm), - AppLocalizations.of(context)!.zeiteinstellung: TextEditingController(text: selectedMEZ), - AppLocalizations.of(context)!.platzung: TextEditingController(text: selectedPlatzung), - AppLocalizations.of(context)!.ktage1: kTage1C, - AppLocalizations.of(context)!.ktage1: kTage2C, - AppLocalizations.of(context)!.location: standortC, - }; - - for (var entry in fields.entries) { - if (entry.value.text.isEmpty) { - emptyFields.add(entry.key); - } - } - - empty = false; - if (emptyFields.isNotEmpty) empty = true; - - return emptyFields; - } - - // If the user decides to safe his values as a template this function is called to save the values in the database - // If the user already edits a template this template will be upadted otherwise a new one will be created - void saveTemplate() async { - var placeDB = DBHelper(); - - Map templates = getPlace(); - - if (widget.isTemplate) { - await placeDB.updateTemplate(templates); - } else { - await placeDB.addTemplate(templates); - } - } - - // 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([bool sent = false]) async { - var placeDB = DBHelper(); - Map place = getPlace(); - - // 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); - } - } - - // 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: standortC, - localization: AppLocalizations.of(context)!.altstort, - ), - ), - 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(() { - selectedStatus = status; - }); - }, - ), - VarTextField( - textController: betreuungC, - localization: AppLocalizations.of(context)!.betreuung, - dbName: "Betreuung", - required: false), - const SizedBox( - height: 20, - ), - VarTextField( - textController: cid, - localization: AppLocalizations.of(context)!.camLink, - dbName: "CID", - required: true), - VarTextField( - textController: ffTypC, - localization: AppLocalizations.of(context)!.fftyp, - dbName: "FFTyp", - required: true), - 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; - }); - }, - ), - const SizedBox( - height: 15, - ), - VarTextField( - textController: kSchloNrC, - localization: AppLocalizations.of(context)!.kschlonr, - dbName: "KSchloNr", - required: false), - const SizedBox( - height: 5, - ), - VarTextField( - textController: rudelC, - localization: AppLocalizations.of(context)!.rudel, - dbName: "Rudel", - required: true), - const SizedBox( - height: 15, - ), - ], - )), - - // Second step - Step( - title: Text(AppLocalizations.of(context)!.secondstep), - content: Column( - children: [ - Row( - children: [ - Column( - children: [ - Text(currentPosition.latitude.toString()), - Text(currentPosition.longitude.toString()), - ], - ), - const SizedBox( - width: 15, - ), - ElevatedButton( - onPressed: () async { - final result = await Navigator.of(context) - .push( - MaterialPageRoute(builder: (context) { - return Karte( - ortInfoC: ortInfoC, - beiOrtC: beiOrtC, - currentPosition: currentPosition, - onPositionChange: (updatedPosition) { - setState(() { - currentPosition = updatedPosition; - }); - }, - ); - })); - 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: bLandC, - localization: AppLocalizations.of(context)!.bland, - dbName: "BLand", - required: true, - defaultValue: "bLand", - ), - VarTextField( - textController: lkrC, - localization: AppLocalizations.of(context)!.lkr, - dbName: "Lkr", - required: true), - VarTextField( - textController: beiOrtC, - localization: AppLocalizations.of(context)!.beiort, - dbName: "BeiOrt", - required: true), - VarTextField( - textController: ortInfoC, - localization: AppLocalizations.of(context)!.ortinfo, - dbName: "OrtInfo", - required: false), - 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; - }); - }, - ), - ], - )), - // Third step - Step( - title: Text(AppLocalizations.of(context)!.thirdstep), - content: Column( - children: [ - Datum( - initDatum: datum, - onDateChanged: (value) { - datum = value; - }, - ), - KontDat( - initKontDat: kontDat, - onDateChanged: (value) { - setState(() { - kontDat = value; - }); - }, - ), - 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: kTage1C, localization: AppLocalizations.of(context)!.ktage1, dbName: "KTage1", required: true)) - ], - ), - - - Row( - children: [ - Expanded( - child: Text( AppLocalizations.of(context)!.ktage2)), - const SizedBox(width: 15,), - Expanded( - flex: 4, - child: VarTextField(otherDefault: "48", textController: kTage2C, localization: AppLocalizations.of(context)!.ktage2, dbName: "KTage2", required: true)) - ], - ), - - const SizedBox( - height: 20, - ), - Row( - children: [ - AbbauDat( - initAbbauDat: abbauDat, - onDateChanged: (value) { - abbauDat = value; - }, - ), - ], - ), - const SizedBox( - height: 20, - ), - VarTextField( - textController: auftragC, - localization: AppLocalizations.of(context)!.auftrag, - dbName: "Auftrag", - required: false), - VarTextField( - textController: kontAbspC, - localization: AppLocalizations.of(context)!.kontabsp, - dbName: "KontAbsp", - required: false), - VarTextField( - textController: sonstBemC, - localization: - AppLocalizations.of(context)!.sonstbemerkungen, - dbName: "SonstBem", - required: false), - ], - )), - // Fourth step - Step( - title: Text(AppLocalizations.of(context)!.fourthstep), - content: Column( - children: [ - VarTextField( - textController: adresse1C, - localization: AppLocalizations.of(context)!.adresse1, - dbName: "Adresse1", - required: true, - defaultValue: "addresse1", - ), - VarTextField( - textController: adresse2C, - localization: AppLocalizations.of(context)!.adresse2, - dbName: "Adresse2", - required: false), - VarTextField( - textController: adresse3C, - localization: AppLocalizations.of(context)!.adresse3, - dbName: "Adresse2", - required: false), - const SizedBox( - height: 15, - ), - VarTextField( - textController: fKontakt1C, - localization: AppLocalizations.of(context)!.fkontakt1, - dbName: "FKontakt1", - required: false), - VarTextField( - textController: fKontakt2C, - localization: AppLocalizations.of(context)!.fkontakt2, - dbName: "FKontakt2", - required: false), - VarTextField( - textController: fKontakt3C, - localization: AppLocalizations.of(context)!.fkontakt3, - dbName: "FKontakt3", - required: false), - VarTextField( - textController: intKommC, - localization: AppLocalizations.of(context)!.intkomm, - dbName: "IntKomm", - required: false), - ], - )) - ]; - - // 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) { - saveTemplate(); - setState(() { - currentStep += 1; - }); - } else { - List emptyFields = validateData(); - // ! always filled out - // empty = false; - if (widget.isSent) { - Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false); - } else if (empty == true) { - showTemplateDialog(emptyFields); - return; - } else if (empty == false) { - await showSaveOptionsDialog(); - } - } - }, - onStepCancel: () { - if (currentStep == 0) { - Navigator.pop(context); - } else { - setState(() { - currentStep -= 1; - }); - } - }))); - } -} diff --git a/lib/screens/addCam/exceptions/location_disabled_exception.dart b/lib/screens/addCam/exceptions/location_disabled_exception.dart new file mode 100644 index 0000000..4b33438 --- /dev/null +++ b/lib/screens/addCam/exceptions/location_disabled_exception.dart @@ -0,0 +1 @@ +class LocationDisabledException implements Exception {} diff --git a/lib/screens/addCam/exceptions/location_forbidden_exception.dart b/lib/screens/addCam/exceptions/location_forbidden_exception.dart new file mode 100644 index 0000000..a878825 --- /dev/null +++ b/lib/screens/addCam/exceptions/location_forbidden_exception.dart @@ -0,0 +1 @@ +class LocationForbiddenException implements Exception{} diff --git a/lib/screens/addCam/services/geolocator_service.dart b/lib/screens/addCam/services/geolocator_service.dart new file mode 100644 index 0000000..5253446 --- /dev/null +++ b/lib/screens/addCam/services/geolocator_service.dart @@ -0,0 +1,26 @@ +import 'package:fforte/screens/addCam/exceptions/location_disabled_exception.dart'; +import 'package:fforte/screens/addCam/exceptions/location_forbidden_exception.dart'; +import 'package:geolocator/geolocator.dart'; + +class GeolocatorService { + // determine live position with checks for denied permission and turned off location service + static Future deteterminePosition() async { + bool locationEnabled; + LocationPermission permissionGiven; + + locationEnabled = await Geolocator.isLocationServiceEnabled(); + if (!locationEnabled) { + throw LocationDisabledException(); + } + + permissionGiven = await Geolocator.checkPermission(); + if (permissionGiven == LocationPermission.denied) { + permissionGiven = await Geolocator.requestPermission(); + if (permissionGiven == LocationPermission.denied || permissionGiven == LocationPermission.deniedForever) { + throw LocationForbiddenException(); + } + } + + return await Geolocator.getCurrentPosition(); + } +} diff --git a/lib/methods/http_request.dart b/lib/screens/sharedMethods/http_request.dart similarity index 100% rename from lib/methods/http_request.dart rename to lib/screens/sharedMethods/http_request.dart diff --git a/lib/screens/sharedMethods/save_file.dart b/lib/screens/sharedMethods/save_file.dart new file mode 100644 index 0000000..e71bc31 --- /dev/null +++ b/lib/screens/sharedMethods/save_file.dart @@ -0,0 +1,21 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:file_picker/file_picker.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +Future saveFile( + Map place, String fileNameLocalization, String placeID) async { + String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); + SharedPreferences prefs = await SharedPreferences.getInstance(); + String jsonPlace = jsonEncode(place); + + if (selectedDirectory == null) { + return; + } + await prefs.setString('saveDir', selectedDirectory); + + File file = File('$selectedDirectory/$fileNameLocalization-$placeID.txt'); + + await file.writeAsString(jsonPlace); +} diff --git a/lib/screens/sharedMethods/save_template.dart b/lib/screens/sharedMethods/save_template.dart new file mode 100644 index 0000000..c7171c4 --- /dev/null +++ b/lib/screens/sharedMethods/save_template.dart @@ -0,0 +1,22 @@ +import 'package:fforte/enums/databases.dart'; +import 'package:fforte/interfaces/i_db.dart'; +import 'package:fforte/methods/excursion_db_helper.dart'; +import 'package:fforte/methods/place_db_helper.dart'; + +void saveTemplate(Map templateData, DatabasesEnum dbType, + bool update) async { + IDb dbHelper; + if (dbType == DatabasesEnum.place) { + dbHelper = PlaceDBHelper(); + } else if (dbType == DatabasesEnum.excursion) { + dbHelper = ExcursionDBHelper(); + } else { + return; + } + + if (update) { + await dbHelper.updateTemplate(templateData); + } else { + await dbHelper.addTemplate(templateData); + } +} diff --git a/lib/methods/send_file.dart b/lib/screens/sharedMethods/send_file.dart similarity index 100% rename from lib/methods/send_file.dart rename to lib/screens/sharedMethods/send_file.dart diff --git a/lib/screens/sharedWidgets/var_text_field.dart b/lib/screens/sharedWidgets/var_text_field.dart index a09f553..8fbba0a 100644 --- a/lib/screens/sharedWidgets/var_text_field.dart +++ b/lib/screens/sharedWidgets/var_text_field.dart @@ -48,12 +48,12 @@ class _VarTextFieldState extends State { Future>> _loadData() async { if (widget.dbDesignation == DatabasesEnum.excursion) { - var entries = await PlaceDBHelper().getPlace(); - var templatesEntries = await PlaceDBHelper().getTemplates(); + var entries = await PlaceDBHelper().getAllMainEntries(); + var templatesEntries = await PlaceDBHelper().getAllTemplates(); return [...entries, ...templatesEntries]; } else { - var entries = await ExcursionDBHelper().getExcursionen(); - var templatesEntries = await ExcursionDBHelper().getTemplates(); + var entries = await ExcursionDBHelper().getAllMainEntries(); + var templatesEntries = await ExcursionDBHelper().getAllTemplates(); return [...entries, ...templatesEntries]; } } diff --git a/lib/screens/viewCam/view_cams.dart b/lib/screens/viewCam/view_cams.dart index 7ef703d..465e7b0 100644 --- a/lib/screens/viewCam/view_cams.dart +++ b/lib/screens/viewCam/view_cams.dart @@ -24,8 +24,8 @@ class _ViewCamsState extends State { @override void initState() { super.initState(); - place = PlaceDBHelper().getPlace(); - templates = PlaceDBHelper().getTemplates(); + place = PlaceDBHelper().getAllMainEntries(); + templates = PlaceDBHelper().getAllTemplates(); } // functions to delete all entries LOCALLY @@ -45,9 +45,9 @@ class _ViewCamsState extends State { TextButton( onPressed: () { var placeDB = PlaceDBHelper(); - placeDB.deleteAllPlaces(); + placeDB.deleteAllMainEntries(); setState(() { - place = PlaceDBHelper().getPlace(); + place = PlaceDBHelper().getAllMainEntries(); }); Navigator.of(context).pop(); @@ -64,9 +64,9 @@ class _ViewCamsState extends State { } void delSinglePlace(int id) async { - PlaceDBHelper().deletePlace(id.toString()); + PlaceDBHelper().deleteMainEntryById(id.toString()); setState(() { - place = PlaceDBHelper().getPlace(); + place = PlaceDBHelper().getAllMainEntries(); }); } @@ -88,7 +88,7 @@ class _ViewCamsState extends State { var placeDB = PlaceDBHelper(); placeDB.deleteAllTemplates(); setState(() { - templates = PlaceDBHelper().getTemplates(); + templates = PlaceDBHelper().getAllTemplates(); }); Navigator.of(context).pop(); }, diff --git a/time.txt b/time.txt index e389d04..05fd66a 100644 --- a/time.txt +++ b/time.txt @@ -74,4 +74,5 @@ 17 mär 2h 30min 30 apr 1h 30min 4. mai 45min - 5. mai 2h 15min +5. mai 2h 15min +6. mai 2h 15min