fix(phasen): ohne Tour nur erster Schritt aktiv - Stepper sperrt Beladen/Ausliefern
An einem Tag ohne Tour konnte man in der AppBar durch alle Stepper-Schritte navigieren. Ursache: an leeren Tagen gilt der GETEILTE 'no-tour'-Persistenz- Eimer; einmal dort aufgeschlossener Fortschritt (hohes Max) machte an JEDEM leeren Tag Beladen/Ausliefern anklickbar. - Stepper: ohne geladene Tour (TourEmpty/loading) ist maxReached hart der erste sichtbare Schritt -> weitere Schritte nicht anklickbar, keine Haekchen - PhaseBloc._load: ohne Tour ausschliesslich Eintrittsphase, Persistenz wird weder gelesen noch geschrieben (kein Fortschritt im 'no-tour'-Eimer) - PhaseBloc._set: ohne Tour jeden Vorwaerts-Wechsel verwerfen, nichts persistieren - unabhaengig vom ausloesenden Button/Tap Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -66,6 +66,14 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
|
||||
/// bedeutungslos.
|
||||
String _token() => tourTokenResolver?.call() ?? 'no-tour';
|
||||
|
||||
/// `true`, wenn aktuell eine Tour geladen ist (der Resolver liefert einen
|
||||
/// Token). Ohne Resolver (z. B. in Tests) gilt „Tour vorhanden", damit
|
||||
/// nichts unnötig gesperrt wird.
|
||||
bool _hasTour() {
|
||||
final resolve = tourTokenResolver;
|
||||
return resolve == null || resolve() != null;
|
||||
}
|
||||
|
||||
PhaseReady _ensureReady() {
|
||||
final current = state;
|
||||
return current is PhaseReady
|
||||
@ -106,6 +114,17 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
|
||||
emit(current.withLoaded(event.carId, entry, entry));
|
||||
}
|
||||
|
||||
// Keine Tour geladen (Tag ohne Tour): ausschließlich die Eintrittsphase,
|
||||
// ohne Persistenz zu lesen oder zu schreiben. Der geteilte
|
||||
// 'no-tour'-Eimer darf keinen Fortschritt tragen — sonst wären an jedem
|
||||
// leeren Tag Beladen/Ausliefern anklickbar.
|
||||
if (!_hasTour()) {
|
||||
final entry = _entryPhase();
|
||||
_loadedTokenByCar[event.carId] = token;
|
||||
add(PhaseLoaded(carId: event.carId, phase: entry, maxPhase: entry));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final persisted = await phaseService.load(event.carId, token);
|
||||
final persistedMax = await phaseService.loadMax(event.carId, token);
|
||||
@ -156,9 +175,17 @@ class PhaseBloc extends Bloc<PhaseEvent, PhaseState> {
|
||||
}
|
||||
|
||||
Future<void> _set(PhaseSet event, Emitter<PhaseState> emit) async {
|
||||
final hasTour = _hasTour();
|
||||
// Ohne geladene Tour gibt es nichts zu beladen/auszuliefern: nur die
|
||||
// Eintrittsphase ist erlaubt, jeder Vorwärts-Wechsel wird verworfen —
|
||||
// egal, welcher Button oder Stepper-Tap ihn auslöst.
|
||||
if (!hasTour && event.phase.index > _entryPhase().index) return;
|
||||
final current = _ensureReady();
|
||||
final next = current.withPhase(event.carId, event.phase);
|
||||
emit(next);
|
||||
// Ohne Tour nichts persistieren — der 'no-tour'-Eimer darf keinen
|
||||
// Fortschritt tragen (s. _load).
|
||||
if (!hasTour) return;
|
||||
try {
|
||||
final token = _token();
|
||||
await phaseService.save(event.carId, token, event.phase);
|
||||
|
||||
@ -125,12 +125,19 @@ class PhaseStepper extends StatelessWidget {
|
||||
final carCount = carsState is CarsLoaded ? carsState.cars.length : 0;
|
||||
final phases = visiblePhases ?? _effectivePhases(carCount);
|
||||
|
||||
// Ohne geladene Tour (Tag ohne Tour / noch ladend) ist ausschließlich
|
||||
// der erste Schritt aktiv: es gibt nichts zu beladen oder auszuliefern,
|
||||
// also dürfen die weiteren Schritte weder anklickbar noch abgehakt
|
||||
// sein — unabhängig davon, was der PhaseBloc als Max kennt.
|
||||
final hasTour = context.watch<TourBloc>().state is TourLoaded;
|
||||
|
||||
// Höchste erreichte Phase aus dem PhaseBloc — bestimmt, welche
|
||||
// Vorwärts-Sprünge erlaubt sind.
|
||||
final phaseBlocState = context.watch<PhaseBloc>().state;
|
||||
final maxReached = phaseBlocState is PhaseReady
|
||||
final blocMax = phaseBlocState is PhaseReady
|
||||
? (phaseBlocState.maxPhaseFor(carId) ?? currentPhase)
|
||||
: currentPhase;
|
||||
final maxReached = hasTour ? blocMax : phases.first;
|
||||
|
||||
return Material(
|
||||
color: theme.primaryColor,
|
||||
|
||||
Reference in New Issue
Block a user