fertig bis auf Tankstellen und Graph
This commit is contained in:
247
lib/controller/edit_controller.dart
Normal file
247
lib/controller/edit_controller.dart
Normal file
@@ -0,0 +1,247 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_tank_web_app/pages/home_view.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
|
||||
import '../models/tank_model.dart';
|
||||
import '../services/appwrite_service.dart';
|
||||
|
||||
class EditController extends GetxController {
|
||||
final AppwriteService appwriteService = AppwriteService();
|
||||
|
||||
// Form controllers
|
||||
final dateController = TextEditingController();
|
||||
final odometerController = TextEditingController();
|
||||
final litersController = TextEditingController();
|
||||
final pricePerLiterController = TextEditingController();
|
||||
final locationController = TextEditingController();
|
||||
|
||||
// Observable states
|
||||
final isLoading = false.obs;
|
||||
final isNewEntry = true.obs;
|
||||
final calculatedTotal = '0.00'.obs;
|
||||
final isLoadingLocation = false.obs;
|
||||
|
||||
TankModel? editingTankModel;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
// Check if we're editing or creating new
|
||||
if (Get.arguments != null) {
|
||||
editingTankModel = Get.arguments as TankModel;
|
||||
isNewEntry.value = false;
|
||||
_loadExistingData();
|
||||
} else {
|
||||
isNewEntry.value = true;
|
||||
_setDefaultDate();
|
||||
_requestLocation();
|
||||
}
|
||||
|
||||
// Add listeners for automatic calculation
|
||||
litersController.addListener(_calculateTotal);
|
||||
pricePerLiterController.addListener(_calculateTotal);
|
||||
}
|
||||
|
||||
void _loadExistingData() {
|
||||
dateController.text = editingTankModel!.szDate;
|
||||
odometerController.text = editingTankModel!.szOdometer;
|
||||
litersController.text = editingTankModel!.szLiters;
|
||||
pricePerLiterController.text = editingTankModel!.szPricePerLiter;
|
||||
locationController.text = editingTankModel!.szLocation;
|
||||
calculatedTotal.value = editingTankModel!.szPriceTotal;
|
||||
}
|
||||
|
||||
void _setDefaultDate() {
|
||||
final now = DateTime.now();
|
||||
dateController.text =
|
||||
'${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
Future<void> _requestLocation() async {
|
||||
bool serviceEnabled;
|
||||
LocationPermission permission;
|
||||
|
||||
try {
|
||||
isLoadingLocation.value = true;
|
||||
|
||||
// 1. Prüfen, ob Standortdienste aktiviert sind
|
||||
serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) {
|
||||
return Future.error('Standortdienste sind deaktiviert.');
|
||||
}
|
||||
|
||||
// 2. Berechtigungen prüfen
|
||||
permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
return Future.error('Berechtigung verweigert.');
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Position abrufen
|
||||
Position position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: const LocationSettings(
|
||||
accuracy: LocationAccuracy.high,
|
||||
),
|
||||
);
|
||||
|
||||
// 4. Standort über Backend-Proxy abrufen
|
||||
var lat = position.latitude;
|
||||
var lon = position.longitude;
|
||||
|
||||
print('📍 Verwende Backend-Proxy für Geocoding...');
|
||||
String location = await appwriteService.geocodeLocation(lat, lon);
|
||||
locationController.text = location;
|
||||
|
||||
// Info anzeigen basierend auf Ergebnis
|
||||
if (location.startsWith('Lat:')) {
|
||||
Get.snackbar(
|
||||
'Hinweis',
|
||||
'Adresse konnte nicht abgerufen werden. Koordinaten gespeichert.',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.orange[100],
|
||||
colorText: Colors.orange[900],
|
||||
duration: const Duration(seconds: 3),
|
||||
);
|
||||
} else {
|
||||
Get.snackbar(
|
||||
'Erfolg',
|
||||
'Standort: $location',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.green[100],
|
||||
colorText: Colors.green[900],
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Get.snackbar(
|
||||
"Fehler",
|
||||
"Standort konnte nicht abgerufen werden: $e",
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.red[100],
|
||||
colorText: Colors.red[900],
|
||||
);
|
||||
print("Fehler beim Abrufen des Standorts: $e");
|
||||
locationController.text = '';
|
||||
} finally {
|
||||
isLoadingLocation.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void _calculateTotal() {
|
||||
final liters = double.tryParse(litersController.text) ?? 0.0;
|
||||
final pricePerLiter = double.tryParse(pricePerLiterController.text) ?? 0.0;
|
||||
calculatedTotal.value = (liters * pricePerLiter).toStringAsFixed(2);
|
||||
}
|
||||
|
||||
Future<void> selectDate(BuildContext context) async {
|
||||
final DateTime? picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
firstDate: DateTime(2020),
|
||||
lastDate: DateTime.now(),
|
||||
builder: (context, child) {
|
||||
return Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
colorScheme: ColorScheme.light(
|
||||
primary: Colors.blueGrey[700]!,
|
||||
onPrimary: Colors.white,
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (picked != null) {
|
||||
dateController.text =
|
||||
'${picked.year}-${picked.month.toString().padLeft(2, '0')}-${picked.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveTankEntry() async {
|
||||
if (!_validateForm()) {
|
||||
Get.snackbar(
|
||||
'Validierungsfehler',
|
||||
'Bitte füllen Sie alle Pflichtfelder aus',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.red[100],
|
||||
colorText: Colors.red[900],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
final userId = await appwriteService.getCurrentUserId();
|
||||
if (userId == null) {
|
||||
throw Exception('Benutzer nicht eingeloggt');
|
||||
}
|
||||
|
||||
final data = {
|
||||
'userId': userId,
|
||||
'date': dateController.text,
|
||||
'odometer': odometerController.text,
|
||||
'liters': litersController.text,
|
||||
'pricePerLiter': pricePerLiterController.text,
|
||||
'location': locationController.text,
|
||||
};
|
||||
|
||||
bool success;
|
||||
if (isNewEntry.value) {
|
||||
success = await appwriteService.createDocumentInCollection(data);
|
||||
} else {
|
||||
success = await appwriteService.updateDocumentInCollection(
|
||||
editingTankModel!.szDocumentId,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
Get.snackbar(
|
||||
'Erfolgreich',
|
||||
isNewEntry.value
|
||||
? 'Tankeintrag erstellt'
|
||||
: 'Tankeintrag aktualisiert',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.green[100],
|
||||
colorText: Colors.green[900],
|
||||
);
|
||||
Get.offAllNamed(HomePage.namedRoute);
|
||||
} else {
|
||||
throw Exception('Speichern fehlgeschlagen');
|
||||
}
|
||||
} catch (e) {
|
||||
Get.snackbar(
|
||||
'Fehler',
|
||||
'Beim Speichern ist ein Fehler aufgetreten: $e',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.red[100],
|
||||
colorText: Colors.red[900],
|
||||
);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool _validateForm() {
|
||||
return dateController.text.isNotEmpty &&
|
||||
odometerController.text.isNotEmpty &&
|
||||
litersController.text.isNotEmpty &&
|
||||
pricePerLiterController.text.isNotEmpty;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
dateController.dispose();
|
||||
odometerController.dispose();
|
||||
litersController.dispose();
|
||||
pricePerLiterController.dispose();
|
||||
locationController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user