diff --git a/lib/config/environment.dart b/lib/config/environment.dart index 49ddcc1..11566d3 100644 --- a/lib/config/environment.dart +++ b/lib/config/environment.dart @@ -7,7 +7,13 @@ class Environment { static const String appwriteDatabaseId = '68a22ef90021b90f0f43'; static const String ptvApiKey = 'NTYxMDQ3NTY2OWI3NDI5ZGIzZWIxOWNiNTNhMDEwODY6YTQ4MTJhYzYtYmYzOC00ZmE4LTk4YzYtZDBjNzYyZTAyNjBk'; - + static const String locationIQKey = 'pk.dea65023dc6fed25c96902bb97fb231d'; + static const double lat=47.93875449671056; + static const double lon=13.762706553431048; + //https://eu1.locationiq.com/v1/reverse?key=pk.dea65023dc6fed25c96902bb97fb231d&lat=47.93875449671056&lon=13.762706553431048&format=json + static const String locationIQBaseUrl = + 'https://eu1.locationiq.com/v1/reverse?key=$locationIQKey&'; //47.93875449671056, 13.762706553431048 + static const String ptvApiVersion = '3'; // Lokaler Reverse Proxy für Entwicklung (CORS-Workaround) static const String localProxyUrl = 'http://localhost:3000'; static const bool useLocalProxy = diff --git a/lib/controller/edit_controller.dart b/lib/controller/edit_controller.dart index 94674e3..8334807 100644 --- a/lib/controller/edit_controller.dart +++ b/lib/controller/edit_controller.dart @@ -1,10 +1,12 @@ 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/locationiq_model.dart'; import '../models/tank_model.dart'; import '../services/appwrite_service.dart'; +import '../services/location_iq_service.dart'; +import '../pages/home_view.dart'; class EditController extends GetxController { final AppwriteService appwriteService = AppwriteService(); @@ -23,6 +25,7 @@ class EditController extends GetxController { final isLoadingLocation = false.obs; TankModel? editingTankModel; + LocationIQ? currentLocationIQ; @override void onInit() { @@ -36,7 +39,7 @@ class EditController extends GetxController { } else { isNewEntry.value = true; _setDefaultDate(); - _requestLocation(); + _requestLocationIQ(); } // Add listeners for automatic calculation @@ -59,7 +62,79 @@ class EditController extends GetxController { '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}'; } - Future _requestLocation() async { + // Future _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; + // } + // } + + Future _requestLocationIQ() async { bool serviceEnabled; LocationPermission permission; @@ -92,30 +167,11 @@ class EditController extends GetxController { 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), - ); - } + print('📍 Verwende LocationIQ für Geocoding...'); + final LocationIQService locationIQService = LocationIQService(); + await locationIQService.fetchLocationIQ(lat, lon); + currentLocationIQ = locationIQService.locationIQ; + locationController.text = currentLocationIQ?.address?.shortAddress ?? ''; } catch (e) { Get.snackbar( "Fehler", @@ -131,6 +187,9 @@ class EditController extends GetxController { } } + + + void _calculateTotal() { final liters = double.tryParse(litersController.text) ?? 0.0; final pricePerLiter = double.tryParse(pricePerLiterController.text) ?? 0.0; diff --git a/lib/models/locationiq_model.dart b/lib/models/locationiq_model.dart new file mode 100644 index 0000000..cc9d044 --- /dev/null +++ b/lib/models/locationiq_model.dart @@ -0,0 +1,112 @@ +class LocationIQ { + String? placeId; + String? licence; + String? osmType; + String? osmId; + String? lat; + String? lon; + String? displayName; + Address? address; + List? boundingbox; + + LocationIQ({ + this.placeId, + this.licence, + this.osmType, + this.osmId, + this.lat, + this.lon, + this.displayName, + this.address, + this.boundingbox, + }); + + LocationIQ.fromJson(Map json) { + placeId = json['place_id']; + licence = json['licence']; + osmType = json['osm_type']; + osmId = json['osm_id']; + lat = json['lat']; + lon = json['lon']; + displayName = json['display_name']; + address = json['address'] != null + ? Address.fromJson(json['address']) + : null; + boundingbox = json['boundingbox'].cast(); + } + + Map toJson() { + final Map data = {}; + data['place_id'] = placeId; + data['licence'] = licence; + data['osm_type'] = osmType; + data['osm_id'] = osmId; + data['lat'] = lat; + data['lon'] = lon; + data['display_name'] = displayName; + if (address != null) { + data['address'] = address!.toJson(); + } + data['boundingbox'] = boundingbox; + return data; + } +} + +class Address { + String? houseNumber; + String? road; + String? village; + String? county; + String? state; + String? postcode; + String? country; + String? countryCode; + // Optional: Kurzadresse für einfachere Anzeige + String? shortAddress; + + Address({ + this.houseNumber, + this.road, + this.village, + this.county, + this.state, + this.postcode, + this.country, + this.countryCode, + // Optional: Kurzadresse generieren + this.shortAddress, + }); + + Address.fromJson(Map json) { + houseNumber = json['house_number']; + road = json['road']; + village = json['village']; + county = json['county']; + state = json['state']; + postcode = json['postcode']; + country = json['country']; + countryCode = json['country_code']; + // Optional: Kurzadresse generieren (z.B. "Test Street 123, 4812 Test Village") + shortAddress = [ + if (road != null) road, + if (houseNumber != null) '$houseNumber,', + if (postcode != null) postcode, + if (village != null) '$village,', + if (county != null) '$county', + ].join(' '); + } + + Map toJson() { + final Map data = {}; + data['house_number'] = houseNumber; + data['road'] = road; + data['village'] = village; + data['county'] = county; + data['state'] = state; + data['postcode'] = postcode; + data['country'] = country; + data['country_code'] = countryCode; + data['short_address'] = shortAddress; + return data; + } +} diff --git a/lib/services/appwrite_service.dart b/lib/services/appwrite_service.dart index 1c6ba28..7610ce4 100644 --- a/lib/services/appwrite_service.dart +++ b/lib/services/appwrite_service.dart @@ -1,7 +1,7 @@ -import 'dart:convert'; +//import 'dart:convert'; import 'package:appwrite/models.dart'; import 'package:appwrite/appwrite.dart'; -import 'package:http/http.dart' as http; +//import 'package:http/http.dart' as http; import '../config/environment.dart'; class AppwriteService { @@ -168,46 +168,46 @@ class AppwriteService { } } - // Geocode coordinates using local proxy or Appwrite Function - Future geocodeLocation(double lat, double lon) async { - // Wenn lokaler Proxy aktiviert ist, diesen verwenden - if (Environment.useLocalProxy) { - return _geocodeViaLocalProxy(lat, lon); - } + // // Geocode coordinates using local proxy or Appwrite Function + // Future geocodeLocation(double lat, double lon) async { + // // Wenn lokaler Proxy aktiviert ist, diesen verwenden + // if (Environment.useLocalProxy) { + // return _geocodeViaLocalProxy(lat, lon); + // } - // Fallback: Koordinaten zurückgeben - return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; - } + // // Fallback: Koordinaten zurückgeben + // return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; + // } - // Geocoding über lokalen Reverse Proxy - Future _geocodeViaLocalProxy(double lat, double lon) async { - try { - final proxyUrl = '${Environment.localProxyUrl}/?lat=$lat&lon=$lon&apiKey=${Environment.ptvApiKey}'; + // // Geocoding über lokalen Reverse Proxy + // Future _geocodeViaLocalProxy(double lat, double lon) async { + // try { + // final proxyUrl = '${Environment.localProxyUrl}/?lat=$lat&lon=$lon&apiKey=${Environment.ptvApiKey}'; - print('🔄 Verwende lokalen Proxy: ${Environment.localProxyUrl}'); + // print('🔄 Verwende lokalen Proxy: ${Environment.localProxyUrl}'); - final response = await http.get(Uri.parse(proxyUrl)); + // final response = await http.get(Uri.parse(proxyUrl)); - if (response.statusCode == 200) { - final data = jsonDecode(response.body); + // if (response.statusCode == 200) { + // final data = jsonDecode(response.body); - if (data['success'] == true) { - final location = data['location'] as String; - print('✅ Geocoding erfolgreich (Proxy): $location'); - return location; - } else { - print('❌ Geocoding fehlgeschlagen (Proxy): ${data['error']}'); - return data['fallbackLocation'] ?? - 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; - } - } else { - print('⚠️ Proxy Response Status: ${response.statusCode}'); - return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; - } - } catch (e) { - print('❌ Lokaler Proxy nicht erreichbar: $e'); - print('💡 Tipp: Starten Sie den Proxy mit: cd proxy-server && node server.js'); - return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; - } - } + // if (data['success'] == true) { + // final location = data['location'] as String; + // print('✅ Geocoding erfolgreich (Proxy): $location'); + // return location; + // } else { + // print('❌ Geocoding fehlgeschlagen (Proxy): ${data['error']}'); + // return data['fallbackLocation'] ?? + // 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; + // } + // } else { + // print('⚠️ Proxy Response Status: ${response.statusCode}'); + // return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; + // } + // } catch (e) { + // print('❌ Lokaler Proxy nicht erreichbar: $e'); + // print('💡 Tipp: Starten Sie den Proxy mit: cd proxy-server && node server.js'); + // return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}'; + // } + // } } diff --git a/lib/services/location_iq_service.dart b/lib/services/location_iq_service.dart new file mode 100644 index 0000000..f7c580a --- /dev/null +++ b/lib/services/location_iq_service.dart @@ -0,0 +1,73 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first + +import 'dart:convert'; + +import '../config/environment.dart'; +import '../models/locationiq_model.dart'; +import 'package:http/http.dart' as http; + +class LocationIQService { + static final String baseUrl = Environment.locationIQBaseUrl; + late LocationIQ locationIQ; + + Future fetchLocationIQ(double lat, double lon) async { + // Hier würde die eigentliche API-Anfrage an LocationIQ erfolgen + // Zum Beispiel mit http.get() und der URL aus Environment.locationIQUrl + // Die Antwort würde dann in das LocationIQ-Modell umgewandelt werden + // https://eu1.locationiq.com/v1/reverse?key=$locationIQKey&lat=47.93875449671056&lon=13.762706553431048&format=json + // locationIQ = LocationIQ.fromJson(responseData); + // Simulierte Antwort (für Testzwecke) + locationIQ = LocationIQ( + placeId: '12345', + licence: 'Data © OpenStreetMap contributors', + osmType: 'node', + osmId: '67890', + lat: lat.toString(), + lon: lon.toString(), + displayName: 'Test Location', + address: Address( + houseNumber: '123', + road: 'Test Street', + village: 'Test Village', + county: 'Test County', + state: 'Test State', + postcode: '12345', + country: 'Test Country', + countryCode: 'TC', + ), + boundingbox: [ + '47.93875449671056', + '47.93875449671056', + '13.762706553431048', + '13.762706553431048', + ], + ); + + // Http Request + var httpClient = http.Client(); + var url = '$baseUrl&lat=$lat&lon=$lon&format=json'; + print('Fetching LocationIQ data from: $url'); + try { + var response = await httpClient.get(Uri.parse(url)); + if (response.statusCode == 200) { + print('LocationIQ API response: ${response.body}'); + locationIQ = LocationIQ.fromJson( + Map.from( + jsonDecode(response.body) as Map, + ), + ); + print('LocationIQ data parsed successfully: ${locationIQ.displayName}'); + } else { + print('Failed to fetch LocationIQ data. Status code: ${response.statusCode}'); + } + } catch (e) { + print('Error fetching LocationIQ data: $e'); + } finally { + httpClient.close(); + } + } + + + + +} diff --git a/pubspec.lock b/pubspec.lock index c13f101..822578f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" clock: dependency: transitive description: @@ -356,18 +356,18 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.18" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: @@ -545,10 +545,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.9" typed_data: dependency: transitive description: