fix: Fehlerbehandlung beim Laden und Meldungen überarbeiten
Reklamationen der Fahrer: Meldungen verdeckten Buttons, und nach dem Abschluss stand „Lieferung nicht in der Tour gefunden" ohne Ausweg da. Meldungen: - Erfolgs-SnackBars entfernt, bei Erfolg bleibt der Spinner - einheitliche, schwebende Meldungen statt Stau über den Buttons - Server-Rohtexte durch verständliche Texte ersetzt (api_failure_text) Laden: - fehlt eine geöffnete Lieferung, wird die Tour einmal neu geholt; die Meldung kommt nur nach erfolgreichem Abruf ohne die Lieferung - Endlos-Spinner auf Lieferdetail, Filial-Abholung und Beladen ersetzt durch Kopfzeile, Fehlergrund und „Erneut versuchen" - Tour wird nach einem Tageswechsel nachgeladen, offene Seiten bleiben dabei unberührt - Abschluss und Zuweisung überschreiben kein zwischenzeitliches Neuladen, alte Antworten drehen einen Abschluss nicht mehr zurück - leere Server-Antworten gelten als Fehler statt als „keine Daten" Anmeldung: - Token-Erneuerung wartet höchstens 12 s, der native Aufruf läuft weiter - App-Start ohne Netz zeigt einen Hinweis mit „Erneut versuchen" - Fehlerseite der Fahrzeugauswahl bietet „Abmelden" Außerdem Podfile.lock an die Plugins angeglichen. Tests für die neuen Fehlerpfade ergänzt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -17,6 +17,7 @@ import 'package:hl_lieferservice/feature/delivery/detail/presentation/steps/step
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/presentation/steps/step_payment.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/presentation/steps/step_services.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/presentation/steps/step_summary.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/presentation/tour_not_loaded_scaffold.dart';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Backend-TODOs (siehe Roadmap unten in diesem File)
|
||||
@ -83,7 +84,11 @@ class _DeliveryDetailScaffold extends StatefulWidget {
|
||||
_DeliveryDetailScaffoldState();
|
||||
}
|
||||
|
||||
class _DeliveryDetailScaffoldState extends State<_DeliveryDetailScaffold> {
|
||||
class _DeliveryDetailScaffoldState extends State<_DeliveryDetailScaffold>
|
||||
with DeliveryPresenceGuard {
|
||||
@override
|
||||
String get guardedDeliveryId => widget.deliveryId;
|
||||
|
||||
/// „Gearmt" = die Lieferung war während dieser Page-Session aktiv. Nur dann
|
||||
/// poppen wir bei `completed` automatisch zurück zur Übersicht. Öffnet der
|
||||
/// Fahrer eine bereits abgeschlossene Lieferung, bleibt `_armed == false`
|
||||
@ -110,9 +115,8 @@ class _DeliveryDetailScaffoldState extends State<_DeliveryDetailScaffold> {
|
||||
|
||||
/// Nach erfolgreichem Abschluss (aktiv → completed) zurück zur Übersicht.
|
||||
void _onTourState(BuildContext context, TourState state) {
|
||||
if (_popped || state is! TourLoaded) return;
|
||||
final d = _findDelivery(state.details);
|
||||
if (d == null) return;
|
||||
if (_popped || !deliveryStillPresent(context, state)) return;
|
||||
final d = _findDelivery((state as TourLoaded).details)!;
|
||||
if (d.state == DeliveryState.active) {
|
||||
_armed = true;
|
||||
} else if (_armed && d.state == DeliveryState.completed) {
|
||||
@ -129,41 +133,67 @@ class _DeliveryDetailScaffoldState extends State<_DeliveryDetailScaffold> {
|
||||
child: BlocBuilder<TourBloc, TourState>(
|
||||
builder: (context, tourState) {
|
||||
if (tourState is! TourLoaded) {
|
||||
return const Scaffold(
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
return TourNotLoadedScaffold(title: 'Lieferung', state: tourState);
|
||||
}
|
||||
final details = tourState.details;
|
||||
final delivery = _findDelivery(details);
|
||||
if (delivery == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Lieferung')),
|
||||
body: Center(
|
||||
child: Text(
|
||||
'Lieferung ${widget.deliveryId} nicht in der Tour gefunden.',
|
||||
),
|
||||
),
|
||||
);
|
||||
// Der Guard lädt gerade neu oder das Neuladen ist gescheitert.
|
||||
return TourNotLoadedScaffold(title: 'Lieferung', state: tourState);
|
||||
}
|
||||
// Titel = Empfänger vor Ort, wie in den Listen-Kacheln.
|
||||
final recipient = details.recipientOf(delivery);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: theme.primaryColor,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
title: Text(recipient.name),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
_StepHeader(delivery: delivery, details: details),
|
||||
const Divider(height: 1),
|
||||
Expanded(
|
||||
child: _StepBody(delivery: delivery, details: details),
|
||||
// Feste Bedienelemente liegen in den Scaffold-Slots: Nur die kennt
|
||||
// der Scaffold und zeigt SnackBars darüber statt darauf.
|
||||
return BlocSelector<
|
||||
DeliveryWorkflowBloc,
|
||||
DeliveryWorkflowState,
|
||||
WorkflowStep
|
||||
>(
|
||||
selector: (state) => state.step,
|
||||
builder: (context, step) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: theme.primaryColor,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
title: Text(recipient.name),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_BottomNav(delivery: delivery, details: details),
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
_StepHeader(delivery: delivery, details: details),
|
||||
const Divider(height: 1),
|
||||
Expanded(
|
||||
child: _StepBody(delivery: delivery, details: details),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Nur bei aktiver Lieferung — sonst ist Hinzufügen gesperrt.
|
||||
floatingActionButton:
|
||||
step == WorkflowStep.notes &&
|
||||
delivery.state == DeliveryState.active
|
||||
? StepNotesAddButton(delivery: delivery)
|
||||
: null,
|
||||
// Das Padding hält die Leiste über der Tastatur (Eingabefelder
|
||||
// im Step „Services"), was der Slot von sich aus nicht tut.
|
||||
bottomNavigationBar: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.viewInsetsOf(context).bottom,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (step == WorkflowStep.payment)
|
||||
StepPaymentCollectPanel(
|
||||
delivery: delivery,
|
||||
details: details,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_BottomNav(delivery: delivery, details: details),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user