Added custom tour ordering

This commit is contained in:
Dennis Nemec
2025-12-20 21:00:33 +01:00
parent 0c61f65961
commit edb8676f5a
13 changed files with 502 additions and 166 deletions

View File

@ -4,6 +4,7 @@ import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_event.dart';
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_info.dart';
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_list.dart';
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_overview_custom_sort.dart';
import 'package:hl_lieferservice/model/tour.dart';
import '../../../../model/delivery.dart';
@ -11,7 +12,11 @@ import '../../../authentication/bloc/auth_bloc.dart';
import '../../../authentication/bloc/auth_state.dart';
class DeliveryOverview extends StatefulWidget {
const DeliveryOverview({super.key, required this.tour, required this.distances});
const DeliveryOverview({
super.key,
required this.tour,
required this.distances,
});
final Tour tour;
final Map<String, double> distances;
@ -44,9 +49,7 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
}
Future<void> _loadTour() async {
Authenticated state = context
.read<AuthBloc>()
.state as Authenticated;
Authenticated state = context.read<AuthBloc>().state as Authenticated;
context.read<TourBloc>().add(LoadTour(teamId: state.user.number));
}
@ -57,58 +60,47 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
child: ListView(
scrollDirection: Axis.horizontal,
children:
widget.tour.driver.cars.map((car) {
Color? backgroundColor;
Color? iconColor = Theme
.of(context)
.primaryColor;
Color? textColor;
widget.tour.driver.cars.map((car) {
Color? backgroundColor;
Color? iconColor = Theme.of(context).primaryColor;
Color? textColor;
if (_selectedCarId == car.id) {
backgroundColor = Theme
.of(context)
.primaryColor;
textColor = Theme
.of(context)
.colorScheme
.onSecondary;
iconColor = Theme
.of(context)
.colorScheme
.onSecondary;
}
if (_selectedCarId == car.id) {
backgroundColor = Theme.of(context).primaryColor;
textColor = Theme.of(context).colorScheme.onSecondary;
iconColor = Theme.of(context).colorScheme.onSecondary;
}
return Padding(
padding: const EdgeInsets.only(right: 8),
child: GestureDetector(
onTap: () {
setState(() {
_selectedCarId = car.id;
});
},
child: Chip(
backgroundColor: backgroundColor,
label: Row(
children: [
Icon(Icons.local_shipping, color: iconColor, size: 20),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
car.plate,
style: TextStyle(color: textColor, fontSize: 12),
),
return Padding(
padding: const EdgeInsets.only(right: 8),
child: GestureDetector(
onTap: () {
setState(() {
_selectedCarId = car.id;
});
},
child: Chip(
backgroundColor: backgroundColor,
label: Row(
children: [
Icon(Icons.local_shipping, color: iconColor, size: 20),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
car.plate,
style: TextStyle(color: textColor, fontSize: 12),
),
),
],
),
],
),
),
),
),
);
}).toList(),
);
}).toList(),
),
);
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
@ -118,7 +110,12 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
children: [
DeliveryInfo(tour: widget.tour),
Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
padding: const EdgeInsets.only(
left: 10,
right: 10,
top: 15,
bottom: 10,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -126,10 +123,7 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
children: [
Text(
"Fahrten",
style: Theme
.of(context)
.textTheme
.headlineSmall,
style: Theme.of(context).textTheme.headlineSmall,
),
],
),
@ -147,25 +141,41 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
_deliveries = _deliveries.reversed.toList();
});
}
if (value == "custom") {
showDialog(
context: context,
fullscreenDialog: true,
builder: (context) => CustomSortDialog(),
);
}
if (value == "distance") {
// TODO: muss noch implementiert werden
}
});
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'name-asc',
child: Text('Name (A-Z)'),
),
PopupMenuItem<String>(
value: 'name-desc',
child: Text('Name (Z-A)'),
),
PopupMenuItem<String>(
value: 'distance',
child: Text('Entfernung'),
),
],
itemBuilder:
(BuildContext context) => <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'name-asc',
child: Text('Name (A-Z)'),
),
PopupMenuItem<String>(
value: 'name-desc',
child: Text('Name (Z-A)'),
),
PopupMenuItem<String>(
value: 'distance',
child: Text('Entfernung'),
),
PopupMenuItem<String>(
value: 'custom',
child: Text('Eigene Sortierung'),
),
],
child: Icon(Icons.filter_list),
)
),
],
),
),
@ -177,13 +187,13 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
child: DeliveryList(
distances: widget.distances,
deliveries:
_deliveries
.where(
(delivery) =>
delivery.carId == _selectedCarId &&
delivery.allArticlesScanned(),
)
.toList(),
_deliveries
.where(
(delivery) =>
delivery.carId == _selectedCarId &&
delivery.allArticlesScanned(),
)
.toList(),
),
),
],

View File

@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_state.dart';
class CustomSortDialog extends StatefulWidget {
const CustomSortDialog({super.key});
@override
State<StatefulWidget> createState() => _CustomSortDialogState();
}
class _CustomSortDialogState extends State<CustomSortDialog> {
Widget _information() {
return Padding(
padding: EdgeInsets.only(top: 15),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(15),
child: Row(
children: [
Padding(
padding: EdgeInsets.only(right: 15),
child: Icon(Icons.info_outline, color: Colors.blueAccent),
),
Expanded(
child: Text(
"Ziehen Sie die einzelnen Lieferungen mit dem Finger in die gewünschte Position.",
),
),
],
),
),
Divider(),
_sortableList(),
],
),
);
}
Widget _sortableList() {
return BlocBuilder<TourBloc, TourState>(
builder: (context, state) {
final currentState = state;
if (currentState is TourLoaded) {
return Expanded(
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {},
children: currentState.tour.deliveries.indexed.fold([], (
acc,
current,
) {
final delivery = current.$2;
final index = current.$1;
acc.add(
ListTile(
leading: CircleAvatar(
backgroundColor: Theme.of(context).primaryColor,
child: Text(
"${index + 1}",
style: TextStyle(
color: Theme.of(context).colorScheme.onSecondary,
),
),
),
title: Text(delivery.customer.name),
subtitle: Text(delivery.customer.address.toString(), style: TextStyle(fontSize: 11),),
trailing: Icon(Icons.drag_handle),
key: Key("reorder-item-${delivery.id}"),
),
);
return acc;
}),
),
);
}
return Center(child: CircularProgressIndicator());
},
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 20, right: 10, top: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Fahrten sortieren",
style: Theme.of(context).textTheme.headlineSmall,
),
IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(Icons.close),
),
],
),
),
Expanded(child: _information()),
],
),
);
}
}

View File

@ -20,7 +20,12 @@ class _DeliveryOverviewPageState extends State<DeliveryOverviewPage> {
if (state is TourLoaded) {
final currentState = state;
return Center(child: DeliveryOverview(tour: currentState.tour, distances: currentState.distances));
return Center(
child: DeliveryOverview(
tour: currentState.tour,
distances: currentState.distances,
),
);
}
return Container();