new location with locationIQ Model and service

This commit is contained in:
2026-02-18 08:20:37 +01:00
parent f730dabca2
commit 191652c886
6 changed files with 324 additions and 74 deletions

View File

@@ -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 =

View File

@@ -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<void> _requestLocation() async {
// 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;
// }
// }
Future<void> _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;

View File

@@ -0,0 +1,112 @@
class LocationIQ {
String? placeId;
String? licence;
String? osmType;
String? osmId;
String? lat;
String? lon;
String? displayName;
Address? address;
List<String>? boundingbox;
LocationIQ({
this.placeId,
this.licence,
this.osmType,
this.osmId,
this.lat,
this.lon,
this.displayName,
this.address,
this.boundingbox,
});
LocationIQ.fromJson(Map<String, dynamic> 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<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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<String, dynamic> 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<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
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;
}
}

View File

@@ -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<String> 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<String> 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<String> _geocodeViaLocalProxy(double lat, double lon) async {
try {
final proxyUrl = '${Environment.localProxyUrl}/?lat=$lat&lon=$lon&apiKey=${Environment.ptvApiKey}';
// // Geocoding über lokalen Reverse Proxy
// Future<String> _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)}';
// }
// }
}

View File

@@ -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<void> 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<String, dynamic>.from(
jsonDecode(response.body) as Map<String, dynamic>,
),
);
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();
}
}
}