Final commit.
This commit is contained in:
@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/car_selection/bloc/bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/car_selection/bloc/events.dart';
|
||||
import 'package:hl_lieferservice/feature/car_selection/bloc/state.dart';
|
||||
import 'package:hl_lieferservice/feature/cars/bloc/cars_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/cars/bloc/cars_state.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/bloc/phase_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/bloc/phase_event.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/bloc/phase_state.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/bloc/tour_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/bloc/tour_state.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/model/delivery_phase.dart';
|
||||
|
||||
/// Horizontaler Phasen-Stepper für die drei bzw. vier Schritte
|
||||
@ -19,9 +20,9 @@ import 'package:hl_lieferservice/feature/delivery/model/delivery_phase.dart';
|
||||
/// * Ein-Auto-Teams: Sortieren, Beladen, Ausliefern (3 Schritte).
|
||||
/// * Mehr-Auto-Teams: Auswählen, Sortieren, Beladen, Ausliefern (4 Schritte).
|
||||
///
|
||||
/// Die Sichtbarkeitsliste wird intern aus dem [TourBloc] abgeleitet
|
||||
/// (Anzahl `tour.driver.cars`). So müssen Aufrufer den Stepper nicht mit
|
||||
/// Routing-Wissen versorgen — er bleibt eine reine Anzeige-Komponente,
|
||||
/// Die Sichtbarkeitsliste wird intern aus dem [CarsBloc] abgeleitet
|
||||
/// (Anzahl Fahrzeuge im Account). So müssen Aufrufer den Stepper nicht
|
||||
/// mit Routing-Wissen versorgen — er bleibt eine reine Anzeige-Komponente,
|
||||
/// die auf den globalen State reagiert.
|
||||
///
|
||||
/// Verhalten:
|
||||
@ -47,8 +48,8 @@ class PhaseStepper extends StatelessWidget {
|
||||
/// Auto-ID, an der die Phase im [PhaseBloc] gespeichert wird.
|
||||
final String carId;
|
||||
|
||||
/// Optionaler Override für Tests / Sonderfälle. Default: aus TourBloc
|
||||
/// abgeleitet (Anzahl cars im Team).
|
||||
/// Optionaler Override für Tests / Sonderfälle. Default: aus CarsBloc
|
||||
/// abgeleitet (Anzahl cars im Account).
|
||||
final List<DeliveryPhase>? visiblePhases;
|
||||
|
||||
IconData _iconFor(DeliveryPhase phase) {
|
||||
@ -107,18 +108,16 @@ class PhaseStepper extends StatelessWidget {
|
||||
final theme = Theme.of(context);
|
||||
final onPrimary = theme.colorScheme.onPrimary;
|
||||
|
||||
return BlocBuilder<TourBloc, TourState>(
|
||||
return BlocBuilder<CarsBloc, CarsState>(
|
||||
// Stepper reagiert auf cars.length-Änderungen — sonst praktisch statisch.
|
||||
buildWhen: (prev, curr) {
|
||||
if (visiblePhases != null) return prev != curr; // override aktiv
|
||||
final prevCars = prev is TourLoaded ? prev.tour.driver.cars.length : 0;
|
||||
final currCars = curr is TourLoaded ? curr.tour.driver.cars.length : 0;
|
||||
final prevCars = prev is CarsLoaded ? prev.cars.length : 0;
|
||||
final currCars = curr is CarsLoaded ? curr.cars.length : 0;
|
||||
return prevCars != currCars || prev.runtimeType != curr.runtimeType;
|
||||
},
|
||||
builder: (context, tourState) {
|
||||
final carCount = tourState is TourLoaded
|
||||
? tourState.tour.driver.cars.length
|
||||
: 0;
|
||||
builder: (context, carsState) {
|
||||
final carCount = carsState is CarsLoaded ? carsState.cars.length : 0;
|
||||
final phases = visiblePhases ?? _effectivePhases(carCount);
|
||||
|
||||
// Höchste erreichte Phase aus dem PhaseBloc — bestimmt, welche
|
||||
@ -151,27 +150,9 @@ class PhaseStepper extends StatelessWidget {
|
||||
if (state is! CarSelectComplete) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.local_shipping,
|
||||
color: onPrimary,
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
state.selectedCar.plate,
|
||||
style: TextStyle(
|
||||
color: onPrimary,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
return _SelectedCarPill(
|
||||
plate: state.selectedCar.plate,
|
||||
onPrimary: onPrimary,
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -337,6 +318,65 @@ class _StepperItem extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Dezente Pille rechts oben im Header: Lkw-Icon, Plate, kleiner Swap-Button.
|
||||
///
|
||||
/// Visuell zurückhaltend gehalten: leicht durchscheinender Hintergrund auf
|
||||
/// dem Primary-Header, kompakter IconButton — der Plate-Text bleibt
|
||||
/// dominantes Element, der Wechseln-Knopf ist eine sekundäre Geste, die
|
||||
/// erst auf Anfrage benutzt wird.
|
||||
class _SelectedCarPill extends StatelessWidget {
|
||||
const _SelectedCarPill({required this.plate, required this.onPrimary});
|
||||
|
||||
final String plate;
|
||||
final Color onPrimary;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(left: 10, right: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: onPrimary.withValues(alpha: 0.12),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.local_shipping, color: onPrimary, size: 16),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
plate,
|
||||
style: TextStyle(
|
||||
color: onPrimary,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
IconButton(
|
||||
tooltip: 'Fahrzeug wechseln',
|
||||
icon: Icon(
|
||||
Icons.swap_horiz_rounded,
|
||||
// Etwas heller als das Plate, damit der Button als sekundäre
|
||||
// Aktion gelesen wird und das Plate nicht überstrahlt.
|
||||
color: onPrimary.withValues(alpha: 0.85),
|
||||
size: 18,
|
||||
),
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.all(4),
|
||||
constraints: const BoxConstraints(
|
||||
minWidth: 32,
|
||||
minHeight: 32,
|
||||
),
|
||||
splashRadius: 18,
|
||||
onPressed: () =>
|
||||
context.read<CarSelectBloc>().add(CarSelectChange()),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Connector extends StatelessWidget {
|
||||
const _Connector({required this.isPassed});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user