switched to local git instance

This commit is contained in:
Nico
2024-03-07 22:20:36 +01:00
commit 75083f2237
154 changed files with 11663 additions and 0 deletions

View File

@@ -0,0 +1,800 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:fforte/addCam/cam_widgets.dart';
import 'package:fforte/db_helper.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:intl/intl.dart';
import 'package:latlong2/latlong.dart';
import 'package:animations/animations.dart';
class AddCamMain extends StatefulWidget {
final bool isTemplate;
final Map<String, dynamic>? templateData;
const AddCamMain({super.key, this.isTemplate = false, this.templateData});
@override
State<AddCamMain> createState() => _AddCamMainState();
}
class _AddCamMainState extends State<AddCamMain> {
// var declaration
int currentStep = 0;
bool isTemplate = false;
TextEditingController id = TextEditingController();
TextEditingController rudelC = TextEditingController();
TextEditingController eugridC = TextEditingController();
TextEditingController nameVornameC = TextEditingController();
TextEditingController plzOrtC = TextEditingController();
TextEditingController emailTelC = TextEditingController();
TextEditingController bLandC = TextEditingController();
TextEditingController lkrC = TextEditingController();
TextEditingController beiOrtC = TextEditingController();
TextEditingController ortInfoC = TextEditingController();
TextEditingController ffTypC = TextEditingController();
TextEditingController kSchloNrC = TextEditingController();
TextEditingController auftragC = TextEditingController();
TextEditingController absprachenC = TextEditingController();
TextEditingController sonstBemerkungenC = TextEditingController();
TextEditingController fKontakt1C = TextEditingController();
TextEditingController fKontakt2C = TextEditingController();
TextEditingController fKontakt3C = TextEditingController();
TextEditingController altStOrtC = TextEditingController();
TextEditingController kTage1C = TextEditingController();
TextEditingController kTage2C = TextEditingController();
TextEditingController intKommC = TextEditingController();
TextEditingController kontSumC = TextEditingController();
String selectedStatus = 'inaktiv';
String selectedSTTyp = 'opportunistisch';
String selectedFotoFilm = 'foto';
String selectedMEZ = 'mez';
String selectedPlatzung = 'kirrung';
String selectedBearsafe = 'nein';
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);
String datumS = DateFormat('yyyy-MM-dd').format(DateTime.now());
String kontDatS = DateFormat('yyyy-mm-dd').format(DateTime.now());
String abbauDatS = DateFormat('yyyy-mm-dd').format(DateTime.now());
String ausVonS = DateFormat('yyyy-mm-dd').format(DateTime(2000));
String ausBisS = DateFormat('yyyy-mm-dd').format(DateTime(2000));
String protoAmS = DateFormat('yyyy-mm-dd').format(DateTime.now());
DateTime? ausBis;
DateTime? ausVon;
DateTime abbauDat = DateTime.now();
DateTime datum = DateTime.now();
DateTime kontDat = DateTime.now();
DateTime protoAm = DateTime.now();
bool empty = false;
// determine live position with checks for denied permission and turned off location service
Future<Position> _deteterminePosition() async {
bool locationEnabled;
LocationPermission permissionGiven;
locationEnabled = await Geolocator.isLocationServiceEnabled();
if (!locationEnabled) {
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
// ignore: use_build_context_synchronously
content: Text(AppLocalizations.of(context)!.locationDisabled)));
return currentPosition;
}
permissionGiven = await Geolocator.checkPermission();
if (permissionGiven == LocationPermission.denied) {
permissionGiven = await Geolocator.requestPermission();
if (permissionGiven == LocationPermission.denied) {
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
// ignore: use_build_context_synchronously
content: Text(AppLocalizations.of(context)!.locationForbidden)));
return currentPosition;
}
}
if (permissionGiven == LocationPermission.deniedForever) {
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
// ignore: use_build_context_synchronously
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.templateData != null) {
id.text = widget.templateData!['CID'];
rudelC.text = widget.templateData!['Rudel'];
eugridC.text = widget.templateData!['EUGrid'];
nameVornameC.text = widget.templateData!['NameVorname'];
plzOrtC.text = widget.templateData!['PLZOrt'];
emailTelC.text = widget.templateData!['EmailTel'];
bLandC.text = widget.templateData!['BLand'];
lkrC.text = widget.templateData!['Lkr'];
beiOrtC.text = widget.templateData!['BeiOrt'];
ortInfoC.text = widget.templateData!['OrtInfo'];
selectedStatus = widget.templateData!['Status'];
selectedSTTyp = widget.templateData!['STTyp'];
ffTypC.text = widget.templateData!['FFTyp'];
selectedFotoFilm = widget.templateData!['FotoFilm'];
selectedMEZ = widget.templateData!['MEZ'];
selectedPlatzung = widget.templateData!['Platzung'];
kSchloNrC.text = widget.templateData!['KSchloNr'];
selectedBearsafe = widget.templateData!['Bearsafe'];
datumS = widget.templateData!['Datum'];
kontDatS = widget.templateData!['KontDat'];
abbauDatS = widget.templateData!['AbbauDat'];
auftragC.text = widget.templateData!['Auftrag'];
absprachenC.text = widget.templateData!['Absprachen'];
sonstBemerkungenC.text = widget.templateData!['SonstBemerkungen'];
fKontakt1C.text = widget.templateData!['FKontakt1'];
fKontakt2C.text = widget.templateData!['FKontakt2'];
fKontakt3C.text = widget.templateData!['FKontakt3'];
altStOrtC.text = widget.templateData!['AltStOrt'];
ausVonS = widget.templateData!['AusVon'];
ausBisS = widget.templateData!['AusBis'];
kTage1C.text = widget.templateData!['KTage1'].toString();
kTage2C.text = widget.templateData!['KTage2'].toString();
protoAmS = widget.templateData!['ProtoAm'];
intKommC.text = widget.templateData!['IntKomm'];
kontSumC.text = widget.templateData!['KontSum'];
}
}
// Function to show the dialog where the user has to choose if he want to safe his values as a template
Future<void> showTemplateDialog(String emptyField) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!.fieldEmpty),
content: SingleChildScrollView(
child: ListBody(children: <Widget>[Text(emptyField)]),
),
actions: <Widget>[
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<void> showSaveOptionsDialog() async {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!.savemethod),
actions: [
TextButton(
onPressed: () {
Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false);
},
child: Text(AppLocalizations.of(context)!.sendtoserver)),
TextButton(
onPressed: () async {
await saveFile();
// ignore: use_build_context_synchronously
Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false);
},
child: Text(AppLocalizations.of(context)!.saveasfile))
],
);
});
}
Future<void> saveFile() async {
String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
Map<String, dynamic> place = {
'CID': id.text,
'Rudel': rudelC.text,
'EUGrid': eugridC.text,
'Datum': datumS,
'NameVorname': nameVornameC.text,
'PLZOrt': plzOrtC.text,
'EmailTel': emailTelC.text,
'BLand': bLandC.text,
'Lkr': lkrC.text,
'BeiOrt': beiOrtC.text,
'OrtInfo': ortInfoC.text,
'Status': selectedStatus,
'STTyp': selectedSTTyp,
'FFTyp': ffTypC.text,
'FotoFilm': selectedFotoFilm,
'MEZ': selectedMEZ,
'Platzung': selectedPlatzung,
'KSchloNr': kSchloNrC.text,
'Bearsafe': selectedBearsafe,
'KontDat': kontDatS,
'AbbauDat': abbauDatS,
'Auftrag': auftragC.text,
'Absprachen': absprachenC.text,
'SonstBemerkungen': sonstBemerkungenC.text,
'FKontakt1': fKontakt1C.text,
'FKontakt2': fKontakt2C.text,
'FKontakt3': fKontakt3C.text,
'AltStOrt': altStOrtC.text,
'AusVon': ausVonS,
'AusBis': ausBisS,
'KTage1': kTage1C.text,
'KTage2': kTage2C.text,
'ProtoAm': protoAmS,
'IntKomm': intKommC.text,
'KontSum': kontSumC.text,
};
String jsonPlace = jsonEncode(place);
if (selectedDirectory == null) {
return;
}
File file = File('$selectedDirectory/cam-${id.text}.txt');
await file
.writeAsString(jsonPlace);
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Datei gespeichert in $selectedDirectory')));
}
// checks if required fields are not empty. If one is the name will be returned
String validateData() {
Map<String, TextEditingController> fields = {
'CID': id,
'Rudel': rudelC,
'NameVorname': nameVornameC,
'BLand': bLandC,
'Lkr': lkrC,
'BeiOrt': beiOrtC,
'OrtInfo': ortInfoC,
'Status': TextEditingController(text: selectedStatus),
'STTyp': TextEditingController(text: selectedSTTyp),
'FFTyp': ffTypC,
'FotoFilm': TextEditingController(text: selectedFotoFilm),
'MEZ': TextEditingController(text: selectedMEZ),
'Platzung': TextEditingController(text: selectedPlatzung),
'KTage1': kTage1C,
'KTage2': kTage2C,
};
for (var entry in fields.entries) {
if (entry.value.text.isEmpty) {
empty = true;
return entry.key;
} else {
empty = false;
}
}
return "";
}
// 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<String, dynamic> templates = {
'CID': id.text,
'Rudel': rudelC.text,
'EUGrid': eugridC.text,
'Datum': datumS,
'NameVorname': nameVornameC.text,
'PLZOrt': plzOrtC.text,
'EmailTel': emailTelC.text,
'BLand': bLandC.text,
'Lkr': lkrC.text,
'BeiOrt': beiOrtC.text,
'OrtInfo': ortInfoC.text,
'Status': selectedStatus,
'STTyp': selectedSTTyp,
'FFTyp': ffTypC.text,
'FotoFilm': selectedFotoFilm,
'MEZ': selectedMEZ,
'Platzung': selectedPlatzung,
'KSchloNr': kSchloNrC.text,
'Bearsafe': selectedBearsafe,
'KontDat': kontDatS,
'AbbauDat': abbauDatS,
'Auftrag': auftragC.text,
'Absprachen': absprachenC.text,
'SonstBemerkungen': sonstBemerkungenC.text,
'FKontakt1': fKontakt1C.text,
'FKontakt2': fKontakt2C.text,
'FKontakt3': fKontakt3C.text,
'AltStOrt': altStOrtC.text,
'AusVon': ausVonS,
'AusBis': ausBisS,
'KTage1': kTage1C.text,
'KTage2': kTage2C.text,
'ProtoAm': protoAmS,
'IntKomm': intKommC.text,
'KontSum': kontSumC.text,
};
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() async {
var placeDB = DBHelper();
Map<String, dynamic> place = {
'CID': id.text,
'Rudel': rudelC.text,
'EUGrid': eugridC.text,
'Datum': datumS,
'NameVorname': nameVornameC.text,
'PLZOrt': plzOrtC.text,
'EmailTel': emailTelC.text,
'BLand': bLandC.text,
'Lkr': lkrC.text,
'BeiOrt': beiOrtC.text,
'OrtInfo': ortInfoC.text,
'Status': selectedStatus,
'STTyp': selectedSTTyp,
'FFTyp': ffTypC.text,
'FotoFilm': selectedFotoFilm,
'MEZ': selectedMEZ,
'Platzung': selectedPlatzung,
'KSchloNr': kSchloNrC.text,
'Bearsafe': selectedBearsafe,
'KontDat': kontDatS,
'AbbauDat': abbauDatS,
'Auftrag': auftragC.text,
'Absprachen': absprachenC.text,
'SonstBemerkungen': sonstBemerkungenC.text,
'FKontakt1': fKontakt1C.text,
'FKontakt2': fKontakt2C.text,
'FKontakt3': fKontakt3C.text,
'AltStOrt': altStOrtC.text,
'AusVon': ausVonS,
'AusBis': ausBisS,
'KTage1': kTage1C.text,
'KTage2': kTage2C.text,
'ProtoAm': protoAmS,
'IntKomm': intKommC.text,
'KontSum': kontSumC.text,
};
await placeDB.addPlace(place);
}
// 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<Step> getSteps() => [
Step(
title: Text(AppLocalizations.of(context)!.firstStep),
content: Column(
children: [
CamId(id: id),
Rudel(rudelC: rudelC),
Align(
alignment: Alignment.bottomLeft,
child: FFTyp(ffTypC: ffTypC),
),
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Text(AppLocalizations.of(context)!.bearsafe),
],
)),
Bearsafe(
initialBearsafe: selectedBearsafe,
onBearsafeChanged: (bearsafe) {
setState(() {
selectedBearsafe = bearsafe;
});
},
),
const SizedBox(
height: 15,
),
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;
});
},
),
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Text(AppLocalizations.of(context)!.sttyp),
const Text(
'*',
style: TextStyle(color: Colors.red),
)
],
)),
STTyp(
initialSTTyp: selectedSTTyp,
onSTTypChanged: (sttyp) {
setState(() {
selectedSTTyp = sttyp;
});
},
),
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Text(
'${AppLocalizations.of(context)!.foto} ${AppLocalizations.of(context)!.film}'),
const Text(
'*',
style: TextStyle(color: Colors.red),
)
],
)),
FotoFilm(
initialFotoFilm: selectedFotoFilm,
onFotoFilmChanged: (fotofilm) {
setState(() {
selectedFotoFilm = fotofilm;
});
},
),
Align(
alignment: Alignment.bottomLeft,
child: KSchloNr(kSchloNrC: kSchloNrC),
),
const SizedBox(
height: 20,
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Text(AppLocalizations.of(context)!.ktage1),
const Text(
'*',
style: TextStyle(color: Colors.red),
)
],
),
),
KTage1(kTage1C: kTage1C),
const SizedBox(
height: 20,
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Text(AppLocalizations.of(context)!.ktage2),
const Text(
'*',
style: TextStyle(color: Colors.red),
)
],
)),
KTage2(kTage2C: kTage2C),
],
)),
// Date Step
Step(
title: Text(AppLocalizations.of(context)!.date),
content: Column(
children: [
Datum(
datum: datum,
),
const SizedBox(
height: 20,
),
KontDat(kontDat: kontDat),
const SizedBox(
height: 20,
),
AbbauDat(abbauDat: abbauDat),
const SizedBox(
height: 20,
),
AusVon(ausVon: ausVon),
const SizedBox(
height: 20,
),
AusBis(ausBis: ausBis),
const SizedBox(
height: 20,
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Text(AppLocalizations.of(context)!.sommerzeit),
const Text(
'*',
style: TextStyle(color: Colors.red),
)
],
)),
MEZ(
initialMEZ: selectedMEZ,
onMEZChanged: (mez) {
setState(() {
selectedMEZ = mez;
});
},
),
KontSum(kontSumC: kontSumC),
],
)),
// Second step (location)
Step(
title: Text(AppLocalizations.of(context)!.locations),
content: Column(
children: [
Align(
alignment: Alignment.bottomLeft,
child: Text(currentPosition.latitude.toString())),
Align(
alignment: Alignment.bottomLeft,
child: Text(currentPosition.longitude.toString())),
Align(
alignment: Alignment.bottomLeft,
child: ElevatedButton(
onPressed: () async {
final result = await Navigator.of(context)
.push<LatLng>(
MaterialPageRoute(builder: (context) {
return Standort(
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)),
),
Align(
alignment: Alignment.bottomLeft,
child: PLZOrt(plzOrtC: plzOrtC),
),
Align(
alignment: Alignment.bottomLeft,
child: BLand(bLandC: bLandC),
),
Align(
alignment: Alignment.bottomLeft,
child: Lkr(lkrC: lkrC),
),
Align(
alignment: Alignment.bottomLeft,
child: BeiOrt(beiOrtC: beiOrtC),
),
Align(
alignment: Alignment.bottomLeft,
child: OrtInfo(ortInfoC: ortInfoC),
),
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;
});
},
),
Align(
alignment: Alignment.bottomLeft,
child: AltStOrt(altStOrtC: altStOrtC),
),
],
)),
Step(
title: Text(AppLocalizations.of(context)!.secondStep),
content: Column(
children: [
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.bottomLeft,
child: NameVorname(nameVornameC: nameVornameC)),
Align(
alignment: Alignment.bottomLeft,
child: EmailTel(emailTelC: emailTelC),
),
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.bottomLeft,
child: Auftrag(auftragC: auftragC),
),
Align(
alignment: Alignment.bottomLeft,
child: Absprachen(absprachenC: absprachenC),
),
Align(
alignment: Alignment.bottomLeft,
child:
SonstBemerkungen(sonstBemerkungenC: sonstBemerkungenC),
),
Align(
alignment: Alignment.bottomLeft,
child: FKontakt1(fKontakt1C: fKontakt1C),
),
Align(
alignment: Alignment.bottomLeft,
child: FKontakt2(fKontakt2C: fKontakt2C),
),
Align(
alignment: Alignment.bottomLeft,
child: FKontakt3(fKontakt3C: fKontakt3C),
),
Align(
alignment: Alignment.bottomLeft,
child: IntKomm(intKommC: intKommC),
),
],
))
];
// Here the site is built inclusive the steps from above
return Scaffold(
appBar: AppBar(title: Text(AppLocalizations.of(context)!.addCam)),
body: PageTransitionSwitcher(
duration: const Duration(milliseconds: 800),
transitionBuilder: (Widget child, Animation<double> animation,
Animation<double> secondaryAnimation) {
return SharedAxisTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.vertical,
child: child,
);
},
child: Stepper(
key: ValueKey<int>(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) {
setState(() {
currentStep += 1;
});
} else {
String emptyField = validateData();
if (empty == true) {
showTemplateDialog(emptyField);
();
return;
} else if (empty == false) {
saveData();
await showSaveOptionsDialog();
Navigator.pushNamedAndRemoveUntil(
// ignore: use_build_context_synchronously
context, '/home', (route) => false);
}
}
},
onStepCancel: () {
if (currentStep == 0) {
Navigator.pop(context);
} else {
setState(() {
currentStep -= 1;
});
}
})));
}
}

2592
lib/addCam/cam_widgets.dart Normal file

File diff suppressed because it is too large Load Diff

121
lib/db_helper.dart Normal file
View File

@@ -0,0 +1,121 @@
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:io' as io;
import 'package:path/path.dart';
// * Gives the complete functionality for the databases
// ! functions may not be named complete correctly
class DBHelper {
static Database? _placeDB;
// checks if the databses are existing and creates them with the initPlaceDatabase function if not
Future<Database> get placeDB async {
if (_placeDB != null) {
return _placeDB!;
}
_placeDB = await initPlaceDatabase();
return _placeDB!;
}
// Creates the databases with help from the _onCreatePlace function
initPlaceDatabase() async {
io.Directory documentsDirectory = await getApplicationCacheDirectory();
String path = join(documentsDirectory.path, 'placeDB.db');
var placeDB =
await openDatabase(path, version: 1, onCreate: _onCreatePlace);
return placeDB;
}
// The function that helps
_onCreatePlace(Database placeDB, int version) async {
await placeDB.execute(
'CREATE TABLE place (id INTEGER PRIMARY KEY, CID TEXT UNIQUE, Standort TEXT, Rudel TEXT, EUGrid TEXT, Datum TEXT, NameVorname TEXT, PLZOrt TEXT, EmailTel TEXT, BLand TEXT, Lkr TEXT, BeiOrt TEXT, OrtInfo TEXT, Status TEXT, STTyp TEXT, FFTyp TEXT, FotoFilm TEXT, MEZ TEXT, Platzung TEXT, KSchloNr TEXT, Bearsafe TEXT, KontDat TEXT, KontSum TEXT, AbbauDat TEXT, Auftrag TEXT, Absprachen TEXT, SonstBemerkungen TEXT, FKontakt1 TEXT, FKontakt2 TEXT, FKontakt3 TEXT, AltStOrt, AusVon TEXT, AusBis TEXT, KTage1 INTEGER, KTage2 INTEGER, ProtoAm TEXT, IntKomm TEXT, Sent INTEGER DEFAULT 0)');
await placeDB.execute(
'CREATE TABLE templates (id INTEGER PRIMARY KEY, CID TEXT UNIQUE, Standort TEXT, Rudel TEXT, EUGrid TEXT, Datum TEXT, NameVorname TEXT, PLZOrt TEXT, EmailTel TEXT, BLand TEXT, Lkr TEXT, BeiOrt TEXT, OrtInfo TEXT, Status TEXT, STTyp TEXT, FFTyp TEXT, FotoFilm TEXT, MEZ TEXT, Platzung TEXT, KSchloNr TEXT, Bearsafe TEXT, KontDat TEXT, KontSum TEXT, AbbauDat TEXT, Auftrag TEXT, Absprachen TEXT, SonstBemerkungen TEXT, FKontakt1 TEXT, FKontakt2 TEXT, FKontakt3 TEXT, AltStOrt TEXT, AusVon TEXT, AusBis TEXT, KTage1 INTEGER, KTage2 INTEGER, ProtoAm TEXT, IntKomm TEXT)');
}
// Function to add a finished entrie
Future<void> addPlace(Map<String, dynamic> place) async {
var placeDBClient = await placeDB;
// gets an camid if it already exists
final existingCID = await placeDBClient.query(
'place',
where: 'CID = ?',
whereArgs: [place['CID']],
);
// checks if the camid var from before is empty to avoid double entries
if (existingCID.isNotEmpty) {
return;
}
// inserts the entrie in the database
await placeDBClient.insert(
'place',
place,
// replaces the entrie with the new onw if a unique value exists and conflicts
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
// same thing as before but with templatews
Future<void> addTemplate(Map<String, dynamic> templates) async {
var placeDBClient = await placeDB;
final existingCID = await placeDBClient.query(
'templates',
where: 'CID = ?',
whereArgs: [templates['CID']],
);
if (existingCID.isNotEmpty) {
return;
}
await placeDBClient.insert(
'templates',
templates,
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
// Updates a existing template
Future<void> updateTemplate(Map<String, dynamic> template) async {
var placeDBClient = await placeDB;
await placeDBClient.update(
'templates',
template,
where: "CID = ?",
whereArgs: [template['CID']],
);
}
// get the finished entries from db
Future<List<Map<String, dynamic>>> getPlace() async {
var placeDBClient = await placeDB;
return await placeDBClient.query('place');
}
// get the finished templates from db
Future<List<Map<String, dynamic>>> getTemplates() async {
var placeDBClient = await placeDB;
return await placeDBClient.query('templates');
}
// deletes all finished entries from the db LOCALLY
Future<void> deleteAllPlaces() async {
var placeDBClient = await placeDB;
await placeDBClient.delete('place');
}
// deletes all templates from the db LOCALLY
Future<void> deleteAllTemplates() async {
var placeDBClient = await placeDB;
await placeDBClient.delete('templates');
}
}

49
lib/home.dart Normal file
View File

@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'addCam/add_cam_main.dart';
// * The homepage where you can choose to add something or view the database entries
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(AppLocalizations.of(context)!.homePageTitle),
actions: [
PopupMenuButton(
onSelected: (value) {
Navigator.pushNamed(context, value.toString());
},
itemBuilder: (context) => [
PopupMenuItem(
value: '/settings',
child: Text(AppLocalizations.of(context)!.settings),
)
])
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AddCamMain()));
},
child: Text(AppLocalizations.of(context)!.addCam)),
ElevatedButton(onPressed: () => Navigator.pushNamed(context, '/viewCams'),
child: const Text('view Cams')),
],
)),
);
}
}

69
lib/intro_screen.dart Normal file
View File

@@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class IntroScreen extends StatefulWidget {
const IntroScreen({super.key});
@override
State<IntroScreen> createState() => _IntroScreenState();
}
class _IntroScreenState extends State<IntroScreen> {
TextEditingController nameVornameC = TextEditingController();
TextEditingController bLandC = TextEditingController();
Future<void> _saveData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('nameVorname', nameVornameC.text);
await prefs.setString('bLand', bLandC.text);
await prefs.setBool('isFirstLaunch', false);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('FFOrte'),
),
body: Center(
child: Container(
padding: const EdgeInsets.all(31),
child: Column(
children: [
TextField(
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.namevorname),
controller: nameVornameC,
onChanged: (value) => setState(() {
nameVornameC.text = value;
}),
),
const SizedBox(
height: 15,
),
TextField(
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.bland),
controller: bLandC,
onChanged: (value) => setState(() {
bLandC.text = value;
}),
),
const SizedBox(
height: 15,
),
ElevatedButton(
onPressed: () {
_saveData();
Navigator.pushNamedAndRemoveUntil(
context, '/home', (route) => false);
},
child: Text(AppLocalizations.of(context)!.continueB))
],
),
),
),
);
}
}

82
lib/l10n/app_de.arb Normal file
View File

@@ -0,0 +1,82 @@
{
"homePageTitle": "FFOrte",
"addCam": "Kamera hinzufügen",
"completed": "Vollständig",
"uncompleted": "Unvollständig",
"deleteEverything": "Alles löschen?",
"deleteEverythingContent": "Alle Kameras werden lokal gelöscht!",
"camLink": "Link zur Kamera",
"firstStep": "Kamera, Rudel",
"secondStep": "Datum, Kontakt",
"date": "Datum",
"status": "Status",
"viewCamsAppbar": "Kameras ansehen",
"locations": "Standort",
"rudel": "Rudel",
"namevorname": "Name",
"plzort": "PLZ und Ort",
"emailtel": "Email und/oder Telefon",
"bland": "Bundesland",
"lkr": "Landkreis",
"beiort": "Bei Ort",
"ortinfo": "Ort Info",
"aktiv": "Aktiv",
"inaktiv": "Inaktiv",
"opportunistisch": "opportunistisch",
"systematic": "systematisch",
"fftyp": "Fotofallen typ",
"foto": "Foto",
"film": "Film",
"mez": "MEZ",
"unklar": "Unklar",
"intkomm": "Interne Kommunikation",
"kirrung": "Kirrung",
"wasserstelle": "Wasserstelle",
"wald": "Wald",
"wildwechsel": "Wildwechsel",
"wegstrasse": "Weg/Straße",
"kschlonr": "KSchloss Nummer",
"nein": "Nein",
"ja": "Ja",
"pickkontdat": "KontDat Auswählen",
"pickabbaudat": "Abbau datum Auswählen",
"platzung": "Platzung",
"sommerzeit": "sommerzeit",
"auftrag": "Auftrag",
"absprachen": "Absprachen",
"sonstbemerkungen": "Sonstige Bemerkungen",
"fkontakt1": "FKontakt 1",
"fkontakt2": "FKontakt 2",
"fkontakt3": "FKontakt 3",
"hofgarten": "Hof/Garten",
"altstort": "AltStOrt",
"wiesefeld": "Wiese/Feld/offenfläche",
"ausvon": "Aus von",
"nichts": "Nichts",
"ausbis": "Aus Bis",
"ktage1": "KTage 1",
"ktage2": "KTage 2",
"eugrid": "EUGrid",
"pickDate": "Datum Auswählen",
"pickTime": "Zeit Auswählen",
"delAll": "Alle Kameras löschen",
"fieldEmpty": "Folgendes Felde ist leer:",
"cancel": "Abbrechen",
"template": "Als Vorlage speichern",
"openMap": "Karte öffnen",
"saveMap": "Speichern und Schleßen",
"locationDisabled": "Standort ausgeschaltet. Bitte einschalten",
"locationForbidden": "Zugriff auf Standort verweigert. Es ist empfohlen dies zu erlauben",
"map": "Karte",
"markerSet": "Marker gesetzt auf",
"kontsum": "Kontrollsumme",
"bearsafe": "Bärensafe",
"sttyp": "STTyp",
"ort": "Ort",
"continueB": "Weiter",
"settings": "Einstellungen",
"changenamestate": "Name und Bundesland ändern",
"saveasfile": "Als Datei speichern",
"sendtoserver": "Zum Server senden",
"savemethod": "Speichermethode auswählen"
}

378
lib/l10n/app_en.arb Normal file
View File

@@ -0,0 +1,378 @@
{
"homePageTitle": "FFOrte",
"@homePageTitle": {
"description": "The title of the homepage"
},
"addCam": "add Cam",
"@addCam": {
"description": "Button to add a camera"
},
"completed": "Completed",
"@completed": {
"description": "View cams tab titel"
},
"uncompleted": "Uncompleted",
"@uncompleted": {
"description": "View cams tab titel"
},
"deleteEverything": "Delete everything?",
"@deleteEverything": {
"description": "Delete everything Alert Dialog title"
},
"deleteEverythingContent": "Every camera will deleted locally!",
"@deleteEverythingContent": {
"description": "Delete everything Alert Dialog content"
},
"camLink": "Link to cam",
"@camLink": {
"description": "Camera link textfield"
},
"firstStep": "Camera, pack",
"@firstStep": {
"description": "title first step"
},
"date": "Date",
"@date": {
"description": "date step"
},
"settings": "Settings",
"@settings": {
"description": "Einstellungen page titel"
},
"changenamestate": "Change name and state",
"@changename": {
"description": "Change name and state header"
},
"secondStep": "Date, Contact",
"@secondStep": {
"description": "title second step"
},
"viewCamsAppbar": "View cams",
"@viewCamsAppbar": {
"description": "view cams appbar"
},
"locations": "Location",
"@locations": {
"description": "Location textfield"
},
"rudel": "Pack",
"@rudel": {
"description": "Rudel textfield"
},
"namevorname": "Name",
"@namevorname": {
"description": "Name Vorname textfield"
},
"plzort": "Postal code and town",
"@plzort": {
"description": "PLZ Ort textfield"
},
"emailtel": "Email and/or Phone",
"@emailtel": {
"description": "email or phone textfield"
},
"bland": "State",
"@bland": {
"description": "state textfield"
},
"lkr": "country",
"@lkr": {
"description": "lkr textfield"
},
"beiort": "By state",
"@beiort": {
"description": "beiort textfield"
},
"ortinfo": "State info",
"@ortinfo": {
"description": "OrtInfo textfield"
},
"aktiv": "Active",
"@aktiv": {
"description": "Active radiobutton"
},
"inaktiv": "Inactive",
"@inaktiv": {
"description": "Inactive radiobutton"
},
"opportunistisch": "opportunist",
"@opportunistisch": {
"description": "opportunistisch radiobutton"
},
"systematisch": "systematic",
"@systematic": {
"description": "systematic radiobutton"
},
"fftyp": "Photo trap type",
"@fftyp": {
"description": "FFTyp textfield"
},
"foto": "Photo",
"@foto": {
"description": "photo radiobutton"
},
"film": "Film",
"@film": {
"description": "film radiobutton"
},
"mez": "MEZ",
"@mez": {
"description": "mez radiobutton"
},
"unklar": "unclear",
"@unklar": {
"description": "unclear radiobutton"
},
"kirrung": "Kirrung",
"@kirrung": {
"description": "kirrung radiobutton"
},
"wasserstelle": "Water point",
"@wasserstelle": {
"description": "wasserstelle radiobutton"
},
"wald": "Forest",
"@wald": {
"description": "wald radiobutton"
},
"wildwechsel": "Wildchange",
"@wildwechsel": {
"description": "wildwechsel radiobutton"
},
"wegstrasse": "Path/Road",
"@wegstrasse": {
"description": "weg/straße radiobutton"
},
"kschlonr": "KLock number",
"@kschlonr": {
"description": "kschlonr textfield"
},
"nein": "No",
"@nein": {
"description": "no radiobutton"
},
"ja": "Yes",
"@ja": {
"description": "yes radiobutton"
},
"pickkontdat": "Pick KontDat",
"@pickkontdat": {
"description": "pickkontdat button"
},
"pickabbaudat": "Pick Disamble Date",
"@abbaudat": {
"description": "pickabbaudat button"
},
"platzung": "Placement",
"@platzung": {
"description": "platzung header"
},
"sommerzeit": "Summertime",
"@sommerzeit": {
"description": "mez summertime header"
},
"auftrag": "Order",
"@auftrag": {
"description": "Auftrag textfield"
},
"absprachen": "Agreements",
"@absprachen": {
"description": "absprachen textfield"
},
"sonstbemerkungen": "Other remarks",
"@sonstbemerkungen": {
"description": "sonstbemerkungen textfield"
},
"fkontakt1": "FContact 1",
"@fkontakt1": {
"description": "fkontakt1 textfield"
},
"fkontakt2": "FContact 2",
"@fkontakt2": {
"description": "fkontakt2 textfield"
},
"fkontakt3": "FContact 3",
"@fkontakt3": {
"description": "fkontakt3 textfield"
},
"altstort": "AltStOrt",
"@altstort": {
"description": "altstort textfield"
},
"ausvon": "Off from",
"@ausvon": {
"description": "ausvon button"
},
"nichts": "None",
"@nichts": {
"description": "nichts text"
},
"ausbis": "Off till",
"@ausbis": {
"description": "ausbis button"
},
"ktage1": "KDays 1",
"@ktage1": {
"description": "ktage1 text/number field"
},
"ktage2": "KDays 2",
"@ktage2": {
"description": "ktage2 text/number field"
},
"intkomm": "Internal communication",
"@intkomm": {
"description": "intkomm textfield"
},
"kontsum": "Control sum",
"@kontsum": {
"description": "kontsum textfield"
},
"hofgarten": "Yard/Garden",
"@hofgarten": {
"description": "hof/garten radiobutton"
},
"wiesefeld": "Meadow/field/open space",
"@wiesefeld": {
"description": "wiese/feld/offenfläche radiobutton"
},
"eugrid": "EUGrid",
"@eugrid": {
"description": "EUGrid textfield"
},
"pickDate": "Pick Date",
"@pickDate": {
"description": "Pick date button"
},
"pickTime": "Pick Time",
"@pickTime": {
"description": "Pick time button"
},
"delAll": "Delete all cams",
"@delAll": {
"description": "Delete all Cams"
},
"fieldEmpty": "Following Field is empty:",
"@fieldEmpty": {
"description": "field empty error message"
},
"cancel": "Cancel",
"@cancel": {
"description": "cancel"
},
"template": "Save as Template / update",
"@template": {
"description": "Save inputs as templates"
},
"openMap": "Open Map",
"@openMap": {
"description": "Open Map button"
},
"saveMap": "Save and close map",
"@saveMap": {
"description": "Save and close button text"
},
"locationDisabled": "Location Disabled. Please enable it",
"@locationDisabled": {
"description": "Disabled location snackbar"
},
"locationForbidden": "Location forbidden. It is recommended to allow it",
"@locationForbidden": {
"description": "Location forbidden"
},
"map": "Map",
"@map": {
"description": "Map appbar"
},
"status": "Status",
"@status": {
"description": "status header"
},
"bearsafe": "Bearsafe",
"@bearsafe": {
"description": "Bearsafe header"
},
"sttyp": "STTyp",
"@sttyp": {
"description": "sttyp header"
},
"markerSet": "Marker set to",
"@markerSet": {
"description": "Marker set snackbar"
},
"ort": "Place",
"@ort": {
"description": "View specific cam appbar text"
},
"continueB": "continue",
"@continue": {
"description": "continue button on login screen"
},
"saveasfile": "Save as File",
"@saveasfile": {
"description": "Save as file button in save method popup"
},
"sendtoserver": "Send to server",
"@sendtoserver": {
"description": "Send data to server button in save method popup"
},
"savemethod": "Choose safe method",
"@savemethod": {
"description": "Title of save mthod popup"
}
}

5
lib/l10n/l10n.dart Normal file
View File

@@ -0,0 +1,5 @@
import 'package:flutter/material.dart';
class L10n {
static final all = [const Locale('en'), const Locale('de')];
}

55
lib/main.dart Normal file
View File

@@ -0,0 +1,55 @@
import 'package:fforte/addCam/add_cam_main.dart';
import 'package:fforte/intro_screen.dart';
import 'package:fforte/settings.dart';
import 'package:fforte/viewCam/view_cams.dart';
import 'package:flutter/material.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'home.dart';
import 'l10n/l10n.dart';
/* void main() async {
runApp(const MyApp());
} */
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLaunch = prefs.getBool('isFirstLaunch') ?? true;
runApp(MyApp(isFirstLaunch: isFirstLaunch));
}
class MyApp extends StatelessWidget {
final bool isFirstLaunch;
const MyApp({super.key, required this.isFirstLaunch});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FFOrte',
theme:
FlexThemeData.light(scheme: FlexScheme.greenM3, useMaterial3: true),
darkTheme:
FlexThemeData.dark(scheme: FlexScheme.greenM3, useMaterial3: true),
themeMode: ThemeMode.system,
initialRoute: isFirstLaunch ? '/introScreen' : '/home',
supportedLocales: L10n.all,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
routes: {
'/home': (context) => const HomePage(),
'/addCamMain': (context) => const AddCamMain(),
'/viewCams': (context) => const ViewCams(),
'/introScreen': (context) => const IntroScreen(),
'/settings': (context) => const Settings(),
},
);
}
}

101
lib/settings.dart Normal file
View File

@@ -0,0 +1,101 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Settings extends StatefulWidget {
const Settings({super.key});
@override
State<Settings> createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
late Future<String> initName;
late Future<String> initBLand;
TextEditingController nameVornameC = TextEditingController();
TextEditingController bLandC = TextEditingController();
@override
void initState() {
super.initState();
initName = _loadName();
initBLand = _loadBLand();
}
Future<String> _loadName() {
Future<String> initName = Future.delayed(Duration.zero, () async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String initName = prefs.getString('nameVorname') ?? '';
nameVornameC.text = initName;
return initName;
});
return initName;
}
Future<String> _loadBLand() {
Future<String> initBLand = Future.delayed(Duration.zero, () async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String initBLand = prefs.getString('bLand') ?? '';
bLandC.text = initBLand;
return initBLand;
});
return initBLand;
}
void _saveName() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('nameVorname', nameVornameC.text);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(AppLocalizations.of(context)!.settings)),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(AppLocalizations.of(context)!.changenamestate ,style: const TextStyle(fontSize: 20, ),),
FutureBuilder<String>(
future: initName, // your Future<String>
builder:
(BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return TextField(
controller: nameVornameC,
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!.namevorname,
),
);
} else {
// Optionally, return a placeholder widget while waiting
return const CircularProgressIndicator();
}
},
),
FutureBuilder<String>(
future: initBLand,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return TextField(
controller: bLandC,
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.bland),
);
} else {
return const CircularProgressIndicator();
}
},
)
],
),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.save),
onPressed: () {
_saveName();
}),
);
}
}

304
lib/viewCam/view_cams.dart Normal file
View File

@@ -0,0 +1,304 @@
import 'package:fforte/addCam/add_cam_main.dart';
import 'package:fforte/db_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_popup_card/flutter_popup_card.dart';
// * Site that shows all entries in the databases
class ViewCams extends StatefulWidget {
const ViewCams({super.key});
@override
State<ViewCams> createState() => _ViewCamsState();
}
class _ViewCamsState extends State<ViewCams> {
// var declaration
late Future<List<Map<String, dynamic>>> place;
late Future<List<Map<String, dynamic>>> templates;
// loads the entries
@override
void initState() {
super.initState();
place = DBHelper().getPlace();
templates = DBHelper().getTemplates();
}
// functions to delete all entries LOCALLY
void delAllPlaces() async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!.deleteEverything),
content: SingleChildScrollView(
child: ListBody(children: <Widget>[
Text(AppLocalizations.of(context)!.deleteEverythingContent)
]),
),
actions: <Widget>[
TextButton(
onPressed: () {
var placeDB = DBHelper();
placeDB.deleteAllPlaces();
setState(() {
place = DBHelper().getPlace();
});
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(context)!.deleteEverything)),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(context)!.cancel))
],
);
});
}
void delAllTemplates() async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!.deleteEverything),
content: SingleChildScrollView(
child: ListBody(children: <Widget>[
Text(AppLocalizations.of(context)!.deleteEverythingContent)
]),
),
actions: <Widget>[
TextButton(
onPressed: () {
var placeDB = DBHelper();
placeDB.deleteAllTemplates();
setState(() {
templates = DBHelper().getTemplates();
});
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(context)!.deleteEverything)),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(context)!.cancel))
],
);
});
}
// The widet tree with taps to differentiate between templates and finished entries
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(text: AppLocalizations.of(context)!.completed),
Tab(
text: AppLocalizations.of(context)!.uncompleted,
)
]),
title: Text(AppLocalizations.of(context)!.viewCamsAppbar)),
body: TabBarView(
children: [
FutureBuilder<List<Map<String, dynamic>>>(
future: place,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.delete),
onPressed: () {
delAllPlaces();
},
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
Map<String, dynamic> place =
snapshot.data![index];
return ListTile(
title: Text('Place ${index + 1}'),
subtitle: Text(
'ID: ${place['CID']} DATUM: ${place['Datum']}'),
trailing: Checkbox(
value: place['Sent'] == 0 ? false : true,
onChanged: null,
),
onTap: () async {
showPopupCard(
context: context,
builder: (context) {
return PopupCard(
color: Theme.of(context).cardColor,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(12)),
child: Container(
decoration:
BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Theme.of(context).cardColor,
boxShadow: [
BoxShadow(
color: Theme.of(context).primaryColor,
spreadRadius: 7,
blurRadius: 7,
offset: const Offset(0, 3))
]),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'${AppLocalizations.of(context)!.date}: ${place['Datum']}'),
Text(
'${AppLocalizations.of(context)!.rudel}: ${place['Rudel']}'),
Text(
'${AppLocalizations.of(context)!.fftyp}: ${place['Datum']}'),
Text(
'${AppLocalizations.of(context)!.bearsafe}: ${place['Bearsafe']}'),
Text(
'${AppLocalizations.of(context)!.status}: ${place['Status']}'),
Text(
'${AppLocalizations.of(context)!.sttyp}: ${place['STTyp']}'),
Text(
'${AppLocalizations.of(context)!.foto}/${AppLocalizations.of(context)!.film}: ${place['FotoFilm']}'),
Text(
'${AppLocalizations.of(context)!.kschlonr}: ${place['KSchloNr']}'),
Text(
'${AppLocalizations.of(context)!.ktage1}: ${place['KTage1']}'),
Text(
'${AppLocalizations.of(context)!.ktage2}: ${place['KTage2']}'),
Text(
'${AppLocalizations.of(context)!.pickkontdat}: ${place['KontDat']}'),
Text(
'${AppLocalizations.of(context)!.pickabbaudat}: ${place['AbbauDat']}'),
Text(
'${AppLocalizations.of(context)!.ausvon}: ${place['AusVon']}'),
Text(
'${AppLocalizations.of(context)!.ausbis}: ${place['AusBis']}'),
Text(
'${AppLocalizations.of(context)!.mez}: ${place['MEZ']}'),
Text(
'${AppLocalizations.of(context)!.kontsum}: ${place['KontSum']}'),
Text(
'${AppLocalizations.of(context)!.locations}: ${place['Standort']}'),
Text(
'${AppLocalizations.of(context)!.plzort}: ${place['PLZOrt']}'),
Text(
'${AppLocalizations.of(context)!.bland}: ${place['BLand']}'),
Text(
'${AppLocalizations.of(context)!.lkr}: ${place['Lkr']}'),
Text(
'${AppLocalizations.of(context)!.beiort}: ${place['BeiOrt']}'),
Text(
'${AppLocalizations.of(context)!.platzung}: ${place['Platzung']}'),
Text(
'${AppLocalizations.of(context)!.altstort}: ${place['AltStOrt']}'),
Text(
'${AppLocalizations.of(context)!.namevorname}: ${place['NameVorname']}'),
Text(
'${AppLocalizations.of(context)!.emailtel}: ${place['EmailTel']}'),
Text(
'${AppLocalizations.of(context)!.auftrag}: ${place['Auftrag']}'),
Text(
'${AppLocalizations.of(context)!.absprachen}: ${place['absprachen']}'),
Text(
'${AppLocalizations.of(context)!.sonstbemerkungen}: ${place['SonstBemerkungen']}'),
Text(
'${AppLocalizations.of(context)!.fkontakt1}: ${place['FKontakt1']}'),
Text(
'${AppLocalizations.of(context)!.fkontakt2}: ${place['FKontakt2']}'),
Text(
'${AppLocalizations.of(context)!.fkontakt3}: ${place['FKontakt3']}'),
Text(
'${AppLocalizations.of(context)!.intkomm}: ${place['IntKomm']}'),
],
),
),
),
),
);
});
},
);
},
))
],
),
);
}
},
),
FutureBuilder<List<Map<String, dynamic>>>(
future: templates,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.delete),
onPressed: () {
delAllTemplates();
},
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
Map<String, dynamic> templates =
snapshot.data![index];
return ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
AddCamMain(
isTemplate: true,
templateData: templates,
)));
},
title: Text('Place ${index + 1}'),
subtitle: Text(
'ID: ${templates['CID']} DATUM: ${templates['Datum']} RUDEL: ${templates['Rudel']} STATUS: ${templates['Status']}'),
);
}),
)
],
),
);
}
})
],
)),
);
}
}