Final commit.

This commit is contained in:
Dennis Nemec
2026-06-01 17:12:28 +02:00
parent 3ecbc82885
commit a9bf8ecdd1
385 changed files with 29081 additions and 12089 deletions

View File

@ -13,8 +13,17 @@ import 'package:hl_lieferservice/feature/delivery/overview/service/phase_service
/// Default-Eintritt [DeliveryPhase.sortieren].
typedef CarCountResolver = int? Function();
/// Liefert einen Token, der die aktuell geladene Tour-Version identifiziert
/// (typischerweise aus `Tour.syncedAt`). Der [PhaseService] bindet die
/// persistierten Phasen an diesen Token — ein neuer ERP-Sync / Demo-Seed
/// erzeugt einen neuen Token und damit einen frischen Phasen-Stand.
///
/// Liefert `null`, wenn (noch) keine Tour geladen ist; der BLoC nutzt dann
/// einen neutralen Fallback-Token.
typedef TourTokenResolver = String? Function();
/// Zentraler State für die aktuelle Phase je Fahrzeug. Persistiert über
/// [PhaseService] auf datumsbezogene SharedPreferences-Keys (siehe Service).
/// [PhaseService] auf tour-token-bezogene SharedPreferences-Keys (siehe Service).
///
/// Eintrittsphase nach Fahrzeugauswahl:
/// * 1 Auto im Team → [DeliveryPhase.sortieren] (bisheriges Verhalten).
@ -30,9 +39,14 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
/// Provider so verdrahtet, dass sie aus dem [TourBloc] kommt.
final CarCountResolver? carCountResolver;
/// Liefert den Tour-Token (aus `Tour.syncedAt`). Bindet die persistierten
/// Phasen an die aktuelle Tour-Version.
final TourTokenResolver? tourTokenResolver;
PhaseBloc({
PhaseService? phaseService,
this.carCountResolver,
this.tourTokenResolver,
}) : phaseService = phaseService ?? PhaseService(),
super(PhaseInitial()) {
on<PhaseLoadForCar>(_load);
@ -40,6 +54,11 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
on<PhaseSet>(_set);
}
/// Aktueller Tour-Token oder neutraler Fallback, falls noch keine Tour
/// geladen ist (z. B. `TourEmpty`) — dort ist die Phase ohnehin
/// bedeutungslos.
String _token() => tourTokenResolver?.call() ?? 'no-tour';
PhaseReady _ensureReady() {
final current = state;
return current is PhaseReady
@ -62,8 +81,9 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
if (current.phaseByCar.containsKey(event.carId)) return;
try {
final persisted = await phaseService.load(event.carId);
final persistedMax = await phaseService.loadMax(event.carId);
final token = _token();
final persisted = await phaseService.load(event.carId, token);
final persistedMax = await phaseService.loadMax(event.carId, token);
final phase = persisted ?? _entryPhase();
// Max ist mindestens die aktuelle Phase. Falls in der Persistenz ein
// höherer Wert steht (Rücksprung), den nehmen.
@ -75,11 +95,11 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
if (persisted == null) {
// Erste Phase nach Fahrzeugauswahl direkt persistieren, damit
// ein Resume nach App-Neustart die Phase kennt.
await phaseService.save(event.carId, phase);
await phaseService.saveMax(event.carId, maxPhase);
await phaseService.save(event.carId, token, phase);
await phaseService.saveMax(event.carId, token, maxPhase);
} else if (persistedMax == null) {
// Migration: alte Tage ohne Max-Tracking → einmalig nachziehen.
await phaseService.saveMax(event.carId, maxPhase);
await phaseService.saveMax(event.carId, token, maxPhase);
}
add(PhaseLoaded(
@ -109,12 +129,13 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
final next = current.withPhase(event.carId, event.phase);
emit(next);
try {
await phaseService.save(event.carId, event.phase);
final token = _token();
await phaseService.save(event.carId, token, event.phase);
// withPhase hat das Max ggf. hochgezogen — persistieren, damit ein
// Neustart die "höchste erreichte Phase" kennt.
final newMax = next.maxPhaseFor(event.carId);
if (newMax != null) {
await phaseService.saveMax(event.carId, newMax);
await phaseService.saveMax(event.carId, token, newMax);
}
} catch (e, st) {
debugPrint("PhaseBloc._set: $e $st");