Final commit.
This commit is contained in:
@ -1,82 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
|
||||
class DistanceService {
|
||||
static const String GOOGLE_MAPS_API_KEY = 'DEIN_API_KEY_HIER';
|
||||
|
||||
static Future<Position> getCurrentLocation() async {
|
||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) {
|
||||
throw Exception('Location services sind deaktiviert');
|
||||
}
|
||||
|
||||
LocationPermission permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
}
|
||||
|
||||
return await Geolocator.getCurrentPosition();
|
||||
}
|
||||
|
||||
// Adresse in Koordinaten umwandeln (Geocoding)
|
||||
static Future<Map<String, double>> getCoordinates(String address) async {
|
||||
String url =
|
||||
'https://maps.googleapis.com/maps/api/geocode/json'
|
||||
'?address=${Uri.encodeComponent(address)}'
|
||||
'&key=AIzaSyB5_1ftLnoswoy59FzNFkrQ7SSDma5eu5E';
|
||||
|
||||
final response = await http.get(Uri.parse(url));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var json = jsonDecode(response.body);
|
||||
|
||||
if (json['results'].isNotEmpty) {
|
||||
var location = json['results'][0]['geometry']['location'];
|
||||
return {
|
||||
'lat': location['lat'],
|
||||
'lng': location['lng'],
|
||||
};
|
||||
}
|
||||
throw Exception('Adresse nicht gefunden');
|
||||
}
|
||||
throw Exception('Geocoding Fehler: ${response.statusCode}');
|
||||
}
|
||||
|
||||
// Distanz berechnen
|
||||
static Future<double> getDistanceByRoad(String address) async {
|
||||
try {
|
||||
Position currentPos = await getCurrentLocation();
|
||||
Map<String, double> coords = await getCoordinates(address);
|
||||
|
||||
String origin = "${currentPos.latitude},${currentPos.longitude}";
|
||||
String destination = "${coords['lat']},${coords['lng']}";
|
||||
|
||||
String url =
|
||||
'https://maps.googleapis.com/maps/api/distancematrix/json'
|
||||
'?origins=$origin'
|
||||
'&destinations=$destination'
|
||||
'&key=AIzaSyB5_1ftLnoswoy59FzNFkrQ7SSDma5eu5E';
|
||||
|
||||
final response = await http.get(Uri.parse(url));
|
||||
|
||||
debugPrint(response.body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var json = jsonDecode(response.body);
|
||||
|
||||
if (json['rows'][0]['elements'][0]['status'] == 'OK') {
|
||||
int distanceMeters = json['rows'][0]['elements'][0]['distance']['value'];
|
||||
return distanceMeters / 1000; // In km
|
||||
} else {
|
||||
throw Exception('Route nicht gefunden');
|
||||
}
|
||||
} else {
|
||||
throw Exception('API Fehler: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Fehler: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,57 +1,52 @@
|
||||
import 'package:hl_lieferservice/feature/delivery/model/delivery_phase.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// Persistiert die aktuelle Phase pro Fahrzeug. Der Key ist datumsspezifisch,
|
||||
/// damit ein App-Neustart am nächsten Tag automatisch wieder mit Phase 1
|
||||
/// (Sortieren) startet — die Phase eines Vortags hat keine Bedeutung mehr.
|
||||
/// Persistiert die aktuelle Phase pro Fahrzeug.
|
||||
///
|
||||
/// Zusätzlich wird die **höchste am Tag erreichte Phase** pro Fahrzeug
|
||||
/// persistiert (eigener Key-Suffix `_max`). Der Stepper nutzt diesen Wert,
|
||||
/// um Vorwärts-Sprünge auf bereits besuchte Phasen zu erlauben — auch wenn
|
||||
/// der Fahrer zwischenzeitlich zurückgesprungen ist.
|
||||
/// Der Key ist an einen **Tour-Token** gebunden (abgeleitet aus
|
||||
/// `Tour.syncedAt`) statt nur an das Datum. Vorteile:
|
||||
///
|
||||
/// * Ein erneuter ERP-Sync / Demo-Seed schreibt eine neue `syncedAt` → neuer
|
||||
/// Token → die Phasen (inkl. der „erledigt"-Häkchen im Stepper) starten
|
||||
/// frisch. So bleibt ein „Daten-Reset" im Backend nicht an alten lokalen
|
||||
/// Häkchen hängen.
|
||||
/// * Eine Tour von heute hat heutiges `syncedAt` — die Tagesbindung ist
|
||||
/// damit implizit (am nächsten Tag gibt es ohnehin eine neue Tour).
|
||||
/// * Bloßes Weiterscannen (Item-Status) ändert `syncedAt` nicht → der
|
||||
/// Fahrer-Fortschritt bleibt über App-Neustarts derselben Tour erhalten.
|
||||
///
|
||||
/// Zusätzlich wird die **höchste erreichte Phase** pro Fahrzeug persistiert
|
||||
/// (Key-Suffix `_max`). Der Stepper nutzt das, um Vorwärts-Sprünge auf
|
||||
/// bereits besuchte Phasen zu erlauben — auch nach einem Rücksprung.
|
||||
class PhaseService {
|
||||
static const _prefix = "delivery_phase";
|
||||
|
||||
String _key(String carId) {
|
||||
final now = DateTime.now();
|
||||
final date = "${now.year}_${now.month}_${now.day}";
|
||||
return "${_prefix}_${date}_$carId";
|
||||
}
|
||||
String _key(String carId, String token) => "${_prefix}_${token}_$carId";
|
||||
|
||||
String _maxKey(String carId) {
|
||||
final now = DateTime.now();
|
||||
final date = "${now.year}_${now.month}_${now.day}";
|
||||
return "${_prefix}_max_${date}_$carId";
|
||||
}
|
||||
String _maxKey(String carId, String token) =>
|
||||
"${_prefix}_max_${token}_$carId";
|
||||
|
||||
Future<void> save(String carId, DeliveryPhase phase) async {
|
||||
Future<void> save(String carId, String token, DeliveryPhase phase) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_key(carId), phase.persistenceKey);
|
||||
await prefs.setString(_key(carId, token), phase.persistenceKey);
|
||||
}
|
||||
|
||||
Future<DeliveryPhase?> load(String carId) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return DeliveryPhaseExtension.fromPersistenceKey(prefs.getString(_key(carId)));
|
||||
}
|
||||
|
||||
Future<void> saveMax(String carId, DeliveryPhase phase) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_maxKey(carId), phase.persistenceKey);
|
||||
}
|
||||
|
||||
Future<DeliveryPhase?> loadMax(String carId) async {
|
||||
Future<DeliveryPhase?> load(String carId, String token) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return DeliveryPhaseExtension.fromPersistenceKey(
|
||||
prefs.getString(_maxKey(carId)),
|
||||
prefs.getString(_key(carId, token)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, DeliveryPhase>> loadAll(Iterable<String> carIds) async {
|
||||
final result = <String, DeliveryPhase>{};
|
||||
for (final carId in carIds) {
|
||||
final phase = await load(carId);
|
||||
if (phase != null) result[carId] = phase;
|
||||
}
|
||||
return result;
|
||||
Future<void> saveMax(String carId, String token, DeliveryPhase phase) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_maxKey(carId, token), phase.persistenceKey);
|
||||
}
|
||||
|
||||
Future<DeliveryPhase?> loadMax(String carId, String token) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return DeliveryPhaseExtension.fromPersistenceKey(
|
||||
prefs.getString(_maxKey(carId, token)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:hl_lieferservice/model/tour.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class ReorderService {
|
||||
get _path async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final date = DateTime.now();
|
||||
final filename = "custom_sort_${date.year}_${date.month}_${date.day}.json";
|
||||
final path = "${dir.path}/$filename";
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
Future<File> get _file async {
|
||||
final path = await _path;
|
||||
final file = File(path);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
Future<void> saveSortingInformation(
|
||||
Map<String, List<String>> container,
|
||||
) async {
|
||||
debugPrint("CONTAINER: ${jsonEncode(container)}");
|
||||
|
||||
(await _file).writeAsString(jsonEncode(container));
|
||||
}
|
||||
|
||||
Future<void> initializeTour(Tour tour) async {
|
||||
(await _file).create();
|
||||
Map<String, List<String>> sorting = {};
|
||||
|
||||
for (final delivery in tour.deliveries) {
|
||||
if (!sorting.containsKey(delivery.carId.toString())) {
|
||||
sorting[delivery.carId.toString()] = [delivery.id];
|
||||
} else {
|
||||
sorting[delivery.carId.toString()]!.add(delivery.id);
|
||||
}
|
||||
}
|
||||
|
||||
(await _file).writeAsString(jsonEncode({"cars": sorting}));
|
||||
}
|
||||
|
||||
bool orderInformationExist() {
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<Map<String, List<String>>> loadSortingInformation() async {
|
||||
debugPrint("FILE: ${await (await _file).readAsString()}");
|
||||
Map<String, List<String>> container = {};
|
||||
Map<String, dynamic> json = jsonDecode(await (await _file).readAsString());
|
||||
|
||||
if (!json.containsKey("cars")) {
|
||||
throw Exception("No cars found in file");
|
||||
}
|
||||
|
||||
for (final car in json["cars"].entries) {
|
||||
List<String> values = [];
|
||||
|
||||
for (String value in car.value) {
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
container[car.key] = values;
|
||||
}
|
||||
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user