new location with locationIQ Model and service
This commit is contained in:
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
|
||||
112
lib/models/locationiq_model.dart
Normal file
112
lib/models/locationiq_model.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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)}';
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
73
lib/services/location_iq_service.dart
Normal file
73
lib/services/location_iq_service.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
16
pubspec.lock
16
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:
|
||||
|
||||
Reference in New Issue
Block a user