let AI comment everything because well... yeah...

This commit is contained in:
Nico
2025-06-06 21:00:32 +02:00
parent 9c84d0c375
commit cc110ac104
44 changed files with 1230 additions and 646 deletions

View File

@@ -22,9 +22,14 @@ import 'widgets/mez.dart';
import 'widgets/platzung.dart';
import 'widgets/status.dart';
/// Widget for adding or editing camera trap locations
/// Supports template creation, editing existing entries, and new entries
class AddCamMain extends StatefulWidget {
/// Whether this form is being used to create a template
final bool isTemplate;
/// Whether the entry has been sent to the server
final bool isSent;
/// Existing data to populate the form with (for editing)
final Map<String, dynamic>? existingData;
const AddCamMain({
@@ -38,14 +43,17 @@ class AddCamMain extends StatefulWidget {
State<AddCamMain> createState() => _AddCamMainState();
}
/// State class for the camera trap location form
class _AddCamMainState extends State<AddCamMain> {
// var declaration
/// Current step in the multi-step form
int currentStep = 0;
/// Whether this form is being used as a template
late bool isTemplate;
/// Current GPS position, initialized with default values for Germany
Position currentPosition = Position(
longitude: 10.0,
latitude: 51.0,
longitude: 10.0, // Default longitude (roughly center of Germany)
latitude: 51.0, // Default latitude (roughly center of Germany)
timestamp: DateTime.now(),
accuracy: 0.0,
altitude: 0.0,
@@ -56,6 +64,12 @@ class _AddCamMainState extends State<AddCamMain> {
headingAccuracy: 0.0,
);
/// Map containing all form fields with their controllers and required status
/// Organized by steps:
/// - Step 1: Basic information (ID, Status, etc.)
/// - Step 2: Location information
/// - Step 3: Dates and control periods
/// - Step 4: Contact information
Map<String, Map<String, dynamic>> rmap = {
"ID": {"controller": TextEditingController(), "required": false},
// Step 1
@@ -102,6 +116,8 @@ class _AddCamMainState extends State<AddCamMain> {
"Sent": {"controller": TextEditingController(), "required": false},
};
/// Retrieves all field values as a map
/// @return Map of field names to their current values
Map<String, String> getFieldsText() {
Map<String, String> puff = {};
@@ -112,8 +128,12 @@ class _AddCamMainState extends State<AddCamMain> {
return puff;
}
/// Flag indicating whether position is currently being loaded
bool isLoadingPosition = false;
/// Initializes the GPS position
/// Handles location permissions and device settings
/// @return Future<Position> The determined position
Future<Position> _initializePosition() async {
try {
final position = await GeolocatorService.deteterminePosition();

View File

@@ -1,25 +0,0 @@
// Karte
// ! completely new page
// Status
// STTyp
// platzung
// FotoFilm
// MEZ
// KontDat
// AbbauDat

View File

@@ -1,19 +1,34 @@
// * Service for handling GPS location functionality
// * Provides methods for:
// * - Location permission handling
// * - GPS service status checks
// * - Position determination
// * - Always-on location checks
import 'package:fforte/screens/addCam/exceptions/location_disabled_exception.dart';
import 'package:fforte/screens/addCam/exceptions/location_forbidden_exception.dart';
import 'package:fforte/screens/excursion/exceptions/need_always_location_exception.dart';
import 'package:geolocator/geolocator.dart';
/// Service class for handling all GPS location related functionality
class GeolocatorService {
// determine live position with checks for denied permission and turned off location service
/// Determine the current device position with permission checks
/// @param alwaysOnNeeded Whether the app needs always-on location permission
/// @throws LocationDisabledException if location services are disabled
/// @throws LocationForbiddenException if location permission is denied
/// @throws NeedAlwaysLocation if always-on permission is needed but not granted
/// @return Future<Position> The current GPS position
static Future<Position> deteterminePosition({bool alwaysOnNeeded = false}) async {
bool locationEnabled;
LocationPermission permissionGiven;
// Check if location services are enabled
locationEnabled = await Geolocator.isLocationServiceEnabled();
if (!locationEnabled) {
throw LocationDisabledException();
}
// Check and request location permissions if needed
permissionGiven = await Geolocator.checkPermission();
if (permissionGiven == LocationPermission.denied) {
permissionGiven = await Geolocator.requestPermission();
@@ -22,13 +37,16 @@ class GeolocatorService {
}
}
// Check for always-on permission if required
if (alwaysOnNeeded && permissionGiven != LocationPermission.always) {
throw NeedAlwaysLocation();
}
return await Geolocator.getCurrentPosition();
return await Geolocator.getCurrentPosition();
}
/// Check if always-on location permission is enabled
/// @return Future<bool> True if always-on permission is granted or location is disabled
static Future<bool> alwaysPositionEnabled() async {
LocationPermission permissionGiven = await Geolocator.checkPermission();
bool locationEnabled = await Geolocator.isLocationServiceEnabled();

View File

@@ -1,8 +1,18 @@
// * Widget for managing camera trap dismantling dates
// * Features:
// * - Date picker for selecting dismantling date
// * - Date display and reset functionality
// * - Localized text support
import 'package:flutter/material.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for selecting and displaying camera trap dismantling dates
/// Allows users to pick a date or clear the selection
class AbbauDat extends StatefulWidget {
/// Initial dismantling date, can be null if not set
final DateTime? initAbbauDat;
/// Callback function when date is changed
final Function(DateTime) onDateChanged;
const AbbauDat({super.key, required this.initAbbauDat, required this.onDateChanged});
@@ -11,7 +21,9 @@ class AbbauDat extends StatefulWidget {
State<AbbauDat> createState() => _AbbauDatState();
}
/// State class for the dismantling date widget
class _AbbauDatState extends State<AbbauDat> {
/// Currently selected dismantling date
DateTime? abbauDat;
@override
@@ -25,6 +37,7 @@ class _AbbauDatState extends State<AbbauDat> {
return Row(
children: [
Column(children: [
// Date picker button
SizedBox(
width: 140,
child: ElevatedButton(
@@ -38,34 +51,34 @@ class _AbbauDatState extends State<AbbauDat> {
),
Row(
children: [
const SizedBox(
width: 10,
),
Builder(builder: (context) {
if (abbauDat != null) {
return Text(
'${abbauDat?.day}. ${abbauDat?.month}. ${abbauDat?.year}');
} else {
return Text(AppLocalizations.of(context)!.nichts);
}
}),
const SizedBox(
width: 10,
),
ElevatedButton(
onPressed: () {
setState(() {
abbauDat = null;
});
},
child: const Text("X"))
]),
],
)
const SizedBox(width: 10),
// Display selected date or "nothing" text
Builder(builder: (context) {
if (abbauDat != null) {
return Text(
'${abbauDat?.day}. ${abbauDat?.month}. ${abbauDat?.year}');
} else {
return Text(AppLocalizations.of(context)!.nichts);
}
}),
const SizedBox(width: 10),
// Clear date button
ElevatedButton(
onPressed: () {
setState(() {
abbauDat = null;
});
},
child: const Text("X"))
]),
],
)
],
);
}
/// Show date picker dialog and return selected date
/// @return Future<DateTime?> Selected date or null if cancelled
Future<DateTime?> pickDate() async {
final date = await showDatePicker(
context: context,

View File

@@ -1,8 +1,18 @@
// * Widget for selecting camera trap media type
// * Provides radio button selection between:
// * - Photo mode
// * - Film/Video mode
// * Includes localization support
import 'package:flutter/material.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for selecting between photo and film/video mode
/// Uses radio buttons for selection with localized labels
class FotoFilm extends StatefulWidget {
/// Callback function when media type selection changes
final Function(String) onFotoFilmChanged;
/// Initial media type selection ('foto' by default)
final String initialFotoFilm;
const FotoFilm(
@@ -14,7 +24,9 @@ class FotoFilm extends StatefulWidget {
State<FotoFilm> createState() => _FotoFilmState();
}
/// State class for the photo/film selection widget
class _FotoFilmState extends State<FotoFilm> {
/// Currently selected media type
String? _selectedFotoFilm;
@override
@@ -27,6 +39,7 @@ class _FotoFilmState extends State<FotoFilm> {
Widget build(BuildContext context) {
return Column(
children: [
// Photo mode radio button
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.foto),
@@ -41,6 +54,7 @@ class _FotoFilmState extends State<FotoFilm> {
},
),
),
// Film/Video mode radio button
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.film),

View File

@@ -1,4 +1,10 @@
// import 'package:fforte/screens/helper/snack_bar_helper.dart';
// * Interactive map widget for camera trap location selection
// * Features:
// * - OpenStreetMap integration
// * - Location marker placement
// * - GPS coordinates display and saving
// * - Localized interface
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:geolocator/geolocator.dart';
@@ -6,11 +12,18 @@ import 'package:latlong2/latlong.dart';
// import 'package:geocoding/geocoding.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for displaying and interacting with the map
/// Allows users to select and save camera trap locations
class Karte extends StatefulWidget {
/// Controller for nearby location name
final TextEditingController beiOrtC;
/// Controller for location details
final TextEditingController ortInfoC;
/// Controller for longitude coordinate
final TextEditingController decLngC;
/// Controller for latitude coordinate
final TextEditingController decLatC;
/// Current GPS position
final Position currentPosition;
const Karte(
@@ -25,15 +38,20 @@ class Karte extends StatefulWidget {
KarteState createState() => KarteState();
}
/// State class for the map widget
class KarteState extends State<Karte> {
/// Current marker on the map
Marker? currentMarker;
/// Selected position coordinates
LatLng? selectedPosition;
/// Whether the save button should be visible
bool saveVisible = false;
@override
void initState() {
super.initState();
// Initialize marker at current position
currentMarker = Marker(
point: LatLng(
widget.currentPosition.latitude, widget.currentPosition.longitude),
@@ -50,6 +68,7 @@ class KarteState extends State<Karte> {
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.map),
actions: [
// Save location button
Visibility(
visible: saveVisible,
child: Padding(
@@ -76,6 +95,7 @@ class KarteState extends State<Karte> {
),
],
),
// Map display with OpenStreetMap tiles
body: FlutterMap(
mapController: MapController(),
options: MapOptions(
@@ -89,15 +109,21 @@ class KarteState extends State<Karte> {
onTap: _handleTap,
),
children: [
// OpenStreetMap tile layer
TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'de.lupus.apps',
),
// Marker layer
MarkerLayer(markers: [currentMarker!]),
]),
);
}
/// Handle tap events on the map
/// Creates a new marker at the tapped location
/// @param position The tap position on the screen
/// @param latlng The geographical coordinates of the tap
_handleTap(TapPosition position, LatLng latlng) {
setState(() {
currentMarker = Marker(
@@ -111,7 +137,7 @@ class KarteState extends State<Karte> {
);
// selectedPosition = latlng;
saveVisible = true;
});
});
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(
// content: Text(
// "${AppLocalizations.of(context)!.markerSet}\n${selectedPosition!.latitude}\n${selectedPosition!.longitude}")));

View File

@@ -1,8 +1,18 @@
// * Widget for managing camera trap control/check dates
// * Features:
// * - Date picker for selecting control dates
// * - Date display in localized format
// * - Callback support for date changes
import 'package:flutter/material.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for selecting and displaying camera trap control dates
/// Used to schedule when the camera trap should be checked
class KontDat extends StatefulWidget {
/// Initial control date, if any
final DateTime? initKontDat;
/// Callback function when date is changed
final Function(DateTime) onDateChanged;
const KontDat(
@@ -12,7 +22,9 @@ class KontDat extends StatefulWidget {
State<KontDat> createState() => _KontDatState();
}
/// State class for the control date widget
class _KontDatState extends State<KontDat> {
/// Currently selected control date
DateTime? kontDat;
@override
@@ -26,6 +38,7 @@ class _KontDatState extends State<KontDat> {
return Row(
children: [
Row(children: [
// Date picker button
SizedBox(
width: 140,
child: ElevatedButton(
@@ -39,9 +52,8 @@ class _KontDatState extends State<KontDat> {
},
child: Text(AppLocalizations.of(context)!.pickkontdat)),
),
const SizedBox(
width: 10,
),
const SizedBox(width: 10),
// Display selected date in DD.MM.YYYY format
Text(
'${kontDat?.day}. ${kontDat?.month}. ${kontDat?.year}',
),
@@ -50,6 +62,8 @@ class _KontDatState extends State<KontDat> {
);
}
/// Show date picker dialog and return selected date
/// @return Future<DateTime?> Selected date or null if cancelled
Future<DateTime?> pickDate() async {
final date = await showDatePicker(
context: context,

View File

@@ -1,8 +1,18 @@
// * Widget for selecting time zone settings (MEZ/MESZ)
// * Features:
// * - Radio button selection between summer and winter time
// * - Localized labels for time zones
// * - Default selection support
import 'package:flutter/material.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for selecting between summer time (MESZ) and winter time (MEZ)
/// Used to configure camera trap time settings
class MEZ extends StatefulWidget {
/// Callback function when time zone selection changes
final Function(String) onMEZChanged;
/// Initial time zone selection ('sommerzeit' by default)
final String initialMEZ;
const MEZ(
@@ -12,7 +22,9 @@ class MEZ extends StatefulWidget {
State<MEZ> createState() => _MEZState();
}
/// State class for the time zone selection widget
class _MEZState extends State<MEZ> {
/// Currently selected time zone
String? _selectedMEZ;
@override
@@ -25,6 +37,7 @@ class _MEZState extends State<MEZ> {
Widget build(BuildContext context) {
return Column(
children: [
// Summer time (MESZ) radio button
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.sommerzeit),
@@ -39,6 +52,7 @@ class _MEZState extends State<MEZ> {
},
),
),
// Winter time (MEZ) radio button
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.winterzeit),

View File

@@ -1,8 +1,26 @@
// * Widget for selecting camera trap placement type
// * Features:
// * - Multiple placement options via radio buttons
// * - Localized labels for each placement type
// * - Support for initial selection
// * Available placement types:
// * - Bait station (Kirrung)
// * - Water source (Wasserstelle)
// * - Forest (Wald)
// * - Game pass (Wildwechsel)
// * - Path/Road (Weg/Straße)
// * - Farm/Garden (Hof/Garten)
// * - Meadow/Field (Wiese/Feld/Offenfläche)
import 'package:flutter/material.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for selecting the type of location where the camera trap is placed
/// Provides various predefined placement options common in wildlife monitoring
class Platzung extends StatefulWidget {
/// Callback function when placement type selection changes
final Function(String) onPlatzungChanged;
/// Initial placement type selection
final String? initialPlatzung;
const Platzung({
@@ -15,7 +33,9 @@ class Platzung extends StatefulWidget {
State<Platzung> createState() => _PlatzungState();
}
/// State class for the placement type selection widget
class _PlatzungState extends State<Platzung> {
/// Currently selected placement type
String? _selectedPlatzung;
@override
@@ -30,6 +50,7 @@ class _PlatzungState extends State<Platzung> {
Widget build(BuildContext context) {
return Column(
children: [
// Bait station placement option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.kirrung),
@@ -44,6 +65,7 @@ class _PlatzungState extends State<Platzung> {
},
),
),
// Water source placement option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.wasserstelle),
@@ -58,6 +80,7 @@ class _PlatzungState extends State<Platzung> {
},
),
),
// Forest placement option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.wald),
@@ -72,6 +95,7 @@ class _PlatzungState extends State<Platzung> {
},
),
),
// Game pass placement option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.wildwechsel),
@@ -86,6 +110,7 @@ class _PlatzungState extends State<Platzung> {
},
),
),
// Path/Road placement option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.wegstrasse),
@@ -100,6 +125,7 @@ class _PlatzungState extends State<Platzung> {
},
),
),
// Farm/Garden placement option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.hofgarten),
@@ -114,6 +140,7 @@ class _PlatzungState extends State<Platzung> {
},
),
),
// Meadow/Field placement option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.wiesefeld),

View File

@@ -1,8 +1,18 @@
// * Widget for selecting camera trap status
// * Features:
// * - Radio button selection between active and inactive
// * - Localized status labels
// * - Default selection support
import 'package:flutter/material.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for selecting the operational status of a camera trap
/// Allows toggling between active and inactive states
class Status extends StatefulWidget {
/// Callback function when status selection changes
final Function(String) onStatusChanged;
/// Initial status selection ('Aktiv' by default)
final String initialStatus;
const Status(
@@ -12,7 +22,9 @@ class Status extends StatefulWidget {
State<Status> createState() => _StatusState();
}
/// State class for the status selection widget
class _StatusState extends State<Status> {
/// Currently selected status
String? _selectedStatus;
@override
@@ -25,6 +37,7 @@ class _StatusState extends State<Status> {
Widget build(BuildContext context) {
return Column(
children: [
// Active status option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.aktiv),
@@ -39,6 +52,7 @@ class _StatusState extends State<Status> {
},
),
),
// Inactive status option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.inaktiv),

View File

@@ -1,8 +1,19 @@
// * Widget for selecting the sampling type for camera trap monitoring
// * Features:
// * - Two sampling modes: opportunistic and systematic
// * - Radio button selection interface
// * - State management for selection
// * - Callback for selection changes
import 'package:flutter/material.dart';
import 'package:fforte/l10n/app_localizations.dart';
/// Widget for managing sampling type selection
/// Provides choice between opportunistic and systematic sampling
class STTyp extends StatefulWidget {
/// Callback function when sampling type changes
final Function(String) onSTTypChanged;
/// Initial sampling type value
final String initialSTTyp;
const STTyp(
@@ -14,7 +25,9 @@ class STTyp extends StatefulWidget {
State<STTyp> createState() => _STTypState();
}
/// State class for the sampling type selection widget
class _STTypState extends State<STTyp> {
/// Currently selected sampling type
String? _selectedSTTyp;
@override
@@ -27,6 +40,7 @@ class _STTypState extends State<STTyp> {
Widget build(BuildContext context) {
return Column(
children: [
// Opportunistic sampling option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.opportunistisch),
@@ -41,6 +55,7 @@ class _STTypState extends State<STTyp> {
},
),
),
// Systematic sampling option
ListTile(
visualDensity: const VisualDensity(vertical: -4),
title: Text(AppLocalizations.of(context)!.systematisch),