import 'package:hl_lieferservice/domain/entity/tour_details.dart'; /// Lifecycle-States des `TourBloc`. /// /// Bewusst eine sealed-Hierarchie: das UI kann via `switch` exhaustiv /// alle Pfade abbilden und der Compiler meldet, wenn ein neuer Pfad /// dazukommt. sealed class TourState { const TourState(); } /// App-Start, bevor irgendetwas geladen wurde. class TourInitial extends TourState { const TourInitial(); } /// Initial-Load läuft. Wird nur emittiert, wenn vorher kein Tour-State da /// war — für Refresh siehe `TourLoaded.isRefreshing`. class TourLoading extends TourState { const TourLoading(); } /// Initial-Load ist gescheitert. Refresh-Fehler hingegen werden in /// `TourLoaded.refreshError` getragen, damit die alte Tour sichtbar bleibt. class TourLoadFailed extends TourState { const TourLoadFailed({required this.message}); final String message; } /// Erfolgreich geladen — beinhaltet das volle Tour-Aggregat sowie /// UI-relevante Zusatzflags rund um Reorder- und Refresh-Operationen. class TourLoaded extends TourState { const TourLoaded({ required this.details, this.isRefreshing = false, this.isPersistingReorder = false, this.refreshError, this.reorderError, }); final TourDetails details; /// Hintergrund-Reload läuft (Pull-to-Refresh, Provider-Wakeup). UI darf /// die alte Daten weiter zeigen und nur einen schmalen Indikator /// einblenden. final bool isRefreshing; /// `PUT /tours/{id}/delivery-order` läuft. Sortier-Page nutzt das für /// den Bestätigungs-Button. final bool isPersistingReorder; /// Fehler eines Hintergrund-Reloads — bleibt für eine einzelne Snackbar /// hängen und wird beim nächsten Reload geleert. final String? refreshError; /// Fehler des letzten Reorder-Persist-Versuchs. final String? reorderError; TourLoaded copyWith({ TourDetails? details, bool? isRefreshing, bool? isPersistingReorder, Object? refreshError = _sentinel, Object? reorderError = _sentinel, }) { return TourLoaded( details: details ?? this.details, isRefreshing: isRefreshing ?? this.isRefreshing, isPersistingReorder: isPersistingReorder ?? this.isPersistingReorder, refreshError: identical(refreshError, _sentinel) ? this.refreshError : refreshError as String?, reorderError: identical(reorderError, _sentinel) ? this.reorderError : reorderError as String?, ); } /// Spezialfall: Initial-Load ist erfolgreich, aber das Backend hat dem /// angemeldeten Fahrer keine Tour für heute zugewiesen (kein ERP-Sync, /// Urlaub, …). UI kann darauf einen freundlichen Hinweis statt einer /// leeren Liste anzeigen. bool get isEmpty => details.deliveries.isEmpty; } const Object _sentinel = Object(); /// Erfolgs-Spezialform für „heute keine Tour zugewiesen". Wir behandeln das /// als eigenständigen State (statt als `TourLoaded` mit leeren Listen), /// damit das UI im Routing klar trennen kann zwischen „Tour vorhanden, /// gerade keine Lieferungen offen" und „gar keine Tour für heute". class TourEmpty extends TourState { const TourEmpty(); }