From 366a3560dcb076e1867eb4d1e06efabcf7967c57 Mon Sep 17 00:00:00 2001 From: Dennis Nemec Date: Tue, 27 Jan 2026 00:21:23 +0100 Subject: [PATCH] Implemented new custom sort and separated the sorted view for each car --- lib/feature/delivery/bloc/tour_bloc.dart | 68 +++++----------- lib/feature/delivery/bloc/tour_event.dart | 3 +- lib/feature/delivery/bloc/tour_state.dart | 4 +- .../overview/model/sorting_information.dart | 37 +++++---- .../overview/presentation/delivery_list.dart | 37 ++++++--- .../presentation/delivery_overview.dart | 14 ++-- .../delivery_overview_custom_sort.dart | 77 ++++++++++--------- .../presentation/delivery_overview_page.dart | 2 + .../overview/service/reorder_service.dart | 57 +++++++++----- lib/feature/delivery/util.dart | 22 ++++++ .../scan/presentation/scan_screen.dart | 1 + 11 files changed, 181 insertions(+), 141 deletions(-) create mode 100644 lib/feature/delivery/util.dart diff --git a/lib/feature/delivery/bloc/tour_bloc.dart b/lib/feature/delivery/bloc/tour_bloc.dart index 3f11092..ad06b8f 100644 --- a/lib/feature/delivery/bloc/tour_bloc.dart +++ b/lib/feature/delivery/bloc/tour_bloc.dart @@ -8,6 +8,7 @@ import 'package:hl_lieferservice/feature/delivery/overview/model/sorting_informa import 'package:hl_lieferservice/feature/delivery/repository/tour_repository.dart'; import 'package:hl_lieferservice/feature/delivery/overview/service/distance_service.dart'; import 'package:hl_lieferservice/feature/delivery/overview/service/reorder_service.dart'; +import 'package:hl_lieferservice/feature/delivery/util.dart'; import 'package:hl_lieferservice/model/tour.dart'; import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart'; import 'package:hl_lieferservice/widget/operations/bloc/operation_event.dart'; @@ -77,7 +78,7 @@ class TourBloc extends Bloc { event.deliveryId, event.articleId, event.amount, - event.reason + event.reason, ); opBloc.add(FinishOperation()); @@ -106,30 +107,18 @@ class TourBloc extends Bloc { ) async { final currentState = state; if (currentState is TourLoaded) { - int newPosition = - event.newPosition == currentState.sortingInformation.sorting.length - ? event.newPosition - 1 - : event.newPosition; - SortingInformation informationOld = currentState - .sortingInformation - .sorting - .firstWhere((info) => info.position == event.oldPosition); + Map> container = {...currentState.sortingInformation}; - SortingInformation information = currentState.sortingInformation.sorting - .firstWhere((info) => info.position == newPosition); - - information.position = event.oldPosition; - informationOld.position = newPosition; - - await ReorderService().saveSortingInformation( - currentState.sortingInformation, + List reorderedList = reorderList( + container[event.carId.toString()] ?? [], + event.oldPosition, + event.newPosition, ); - emit( - currentState.copyWith( - sortingInformation: currentState.sortingInformation.copyWith(), - ), - ); + container[event.carId.toString()] = reorderedList; + await ReorderService().saveSortingInformation(container); + + emit(currentState.copyWith(sortingInformation: container)); } } @@ -171,9 +160,7 @@ class TourBloc extends Bloc { ) async { try { ReorderService service = ReorderService(); - SortingInformationContainer container = SortingInformationContainer( - sorting: [], - ); + Map> container = {}; // Create empty default value if it does not exist yet if (!service.orderInformationExist()) { @@ -186,25 +173,14 @@ class TourBloc extends Bloc { bool inconsistent = false; for (final delivery in event.tour.deliveries) { - int info = container.sorting.indexWhere( - (info) => info.deliveryId == delivery.id, + int info = container[delivery.carId.toString()]!.indexWhere( + (id) => id == delivery.id, ); - int max = container.sorting.fold(0, (acc, element) { - if (element.position > acc) { - return element.position; - } - return acc; - }); // not found, so add it to the list if (info == -1) { inconsistent = true; - container.sorting.add( - SortingInformation( - deliveryId: delivery.id, - position: container.sorting.isEmpty ? 0 : max + 1, - ), - ); + container[delivery.carId.toString()]!.add(delivery.id); } } @@ -233,13 +209,9 @@ class TourBloc extends Bloc { ), ); - SortingInformationContainer container = SortingInformationContainer( - sorting: [], - ); - for (final (index, delivery) in event.tour.deliveries.indexed) { - container.sorting.add( - SortingInformation(deliveryId: delivery.id, position: index), - ); + Map> container = {}; + for (final delivery in event.tour.deliveries) { + container[delivery.carId.toString()]!.add(delivery.id); } emit( @@ -365,7 +337,9 @@ class TourBloc extends Bloc { ); break; } - } on TourNotFoundException { + } catch (e, st) { + debugPrint("FEHLER beim Scannen eines Artikels: $e"); + debugPrint("$st"); opBloc.add(FailOperation(message: "Fehler beim Scannen des Artikels")); } } diff --git a/lib/feature/delivery/bloc/tour_event.dart b/lib/feature/delivery/bloc/tour_event.dart index b35986f..3bfd729 100644 --- a/lib/feature/delivery/bloc/tour_event.dart +++ b/lib/feature/delivery/bloc/tour_event.dart @@ -35,8 +35,9 @@ class RequestSortingInformationEvent extends TourEvent { class ReorderDeliveryEvent extends TourEvent { int newPosition; int oldPosition; + String carId; - ReorderDeliveryEvent({required this.newPosition, required this.oldPosition}); + ReorderDeliveryEvent({required this.newPosition, required this.oldPosition, required this.carId}); } class TourUpdated extends TourEvent { diff --git a/lib/feature/delivery/bloc/tour_state.dart b/lib/feature/delivery/bloc/tour_state.dart index d81f4ad..6c8f1a1 100644 --- a/lib/feature/delivery/bloc/tour_state.dart +++ b/lib/feature/delivery/bloc/tour_state.dart @@ -31,7 +31,7 @@ class TourLoaded extends TourState { Tour tour; Map? distances; List paymentOptions; - SortingInformationContainer sortingInformation; + Map> sortingInformation; TourLoaded({ required this.tour, @@ -44,7 +44,7 @@ class TourLoaded extends TourState { Tour? tour, Map? distances, List? paymentOptions, - SortingInformationContainer? sortingInformation + Map>? sortingInformation }) { return TourLoaded( tour: tour ?? this.tour, diff --git a/lib/feature/delivery/overview/model/sorting_information.dart b/lib/feature/delivery/overview/model/sorting_information.dart index 56f562e..6029b9e 100644 --- a/lib/feature/delivery/overview/model/sorting_information.dart +++ b/lib/feature/delivery/overview/model/sorting_information.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; class SortingInformation { String deliveryId; @@ -18,36 +19,38 @@ class SortingInformation { } class SortingInformationContainer { - List sorting; + Map> cars; - SortingInformationContainer({required this.sorting}); - - void sort() { - sorting.sort((a, b) => a.position.compareTo(b.position)); - } + SortingInformationContainer({required this.cars}); static SortingInformationContainer fromJson(Map json) { SortingInformationContainer container = SortingInformationContainer( - sorting: [], + cars: {}, ); - for (final info in json["sorting"]) { - container.sorting.add(SortingInformation.fromJson(info)); + for (final car in json["cars"].entries) { + List values = []; + for (String value in car.value) { + values.add(value); + } + + container.cars[car.key] = values; } return container; } Map toJson() { - return { - "sorting": - sorting.map((info) => SortingInformation.toJson(info)).toList(), - }; + Map cars = {}; + + for (final car in this.cars.entries) { + cars[car.key] = car.value; + } + + return {"cars": cars}; } - SortingInformationContainer copyWith({List? sorting}) { - return SortingInformationContainer( - sorting: sorting ?? this.sorting, - ); + SortingInformationContainer copyWith({Map>? sorting}) { + return SortingInformationContainer(cars: sorting ?? cars); } } diff --git a/lib/feature/delivery/overview/presentation/delivery_list.dart b/lib/feature/delivery/overview/presentation/delivery_list.dart index 882da42..fdfe88a 100644 --- a/lib/feature/delivery/overview/presentation/delivery_list.dart +++ b/lib/feature/delivery/overview/presentation/delivery_list.dart @@ -26,18 +26,19 @@ class _DeliveryListState extends State { Widget _showCustomSortedList( List deliveries, - List sortingInformation, + List sortingInformation, Map distances, ) { - List sorted = [...sortingInformation]; - sorted.sort((a, b) => a.position.compareTo(b.position)); - return ListView.separated( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), separatorBuilder: (context, index) => const Divider(height: 0), itemBuilder: (context, index) { - SortingInformation info = sorted[index]; + String id = sortingInformation[index]; Delivery delivery = deliveries.firstWhere( - (delivery) => info.deliveryId == delivery.id, + (delivery) => + id == delivery.id && + delivery.carId == widget.selectedCarId, ); return DeliveryListItem( @@ -45,7 +46,7 @@ class _DeliveryListState extends State { distance: distances[delivery.id] ?? 0.0, ); }, - itemCount: sorted.length, + itemCount: sortingInformation.length, ); } @@ -60,12 +61,24 @@ class _DeliveryListState extends State { .where( (delivery) => delivery.carId == widget.selectedCarId && - delivery.allArticlesScanned() || delivery.state == DeliveryState.finished, + delivery.allArticlesScanned() && + delivery.state != DeliveryState.finished, + ) + .toList(); + + List finishedDeliveries = + currentState.tour.deliveries + .where( + (delivery) => + delivery.state == DeliveryState.finished && + delivery.carId == widget.selectedCarId, ) .toList(); if (deliveries.isEmpty) { return ListView( + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, children: [ Center(child: const Text("Keine Auslieferungen gefunden")), ], @@ -75,8 +88,8 @@ class _DeliveryListState extends State { switch (widget.sortType) { case SortType.custom: return _showCustomSortedList( - deliveries, - currentState.sortingInformation.sorting, + currentState.tour.deliveries, + currentState.sortingInformation[widget.selectedCarId.toString()] ?? [], currentState.distances ?? {}, ); @@ -101,8 +114,12 @@ class _DeliveryListState extends State { break; } + //deliveries.addAll(finishedDeliveries); + return ListView.separated( separatorBuilder: (context, index) => const Divider(height: 0), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) { Delivery delivery = deliveries[index]; diff --git a/lib/feature/delivery/overview/presentation/delivery_overview.dart b/lib/feature/delivery/overview/presentation/delivery_overview.dart index 55cfae8..73ea6c7 100644 --- a/lib/feature/delivery/overview/presentation/delivery_overview.dart +++ b/lib/feature/delivery/overview/presentation/delivery_overview.dart @@ -101,8 +101,8 @@ class _DeliveryOverviewState extends State { Widget build(BuildContext context) { return RefreshIndicator( onRefresh: _loadTour, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: ListView( + //crossAxisAlignment: CrossAxisAlignment.start, children: [ DeliveryInfo(tour: widget.tour), Padding( @@ -150,7 +150,7 @@ class _DeliveryOverviewState extends State { showDialog( context: context, fullscreenDialog: true, - builder: (context) => CustomSortDialog(), + builder: (context) => CustomSortDialog(selectedCarId: _selectedCarId,), ); break; } @@ -195,11 +195,9 @@ class _DeliveryOverviewState extends State { padding: const EdgeInsets.only(left: 10, right: 10, bottom: 20), child: _carSelection(), ), - Expanded( - child: DeliveryList( - selectedCarId: _selectedCarId, - sortType: _sortType, - ), + DeliveryList( + selectedCarId: _selectedCarId, + sortType: _sortType, ), ], ), diff --git a/lib/feature/delivery/overview/presentation/delivery_overview_custom_sort.dart b/lib/feature/delivery/overview/presentation/delivery_overview_custom_sort.dart index c318bde..7289e7b 100644 --- a/lib/feature/delivery/overview/presentation/delivery_overview_custom_sort.dart +++ b/lib/feature/delivery/overview/presentation/delivery_overview_custom_sort.dart @@ -3,33 +3,34 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hl_lieferservice/feature/delivery/bloc/tour_bloc.dart'; import 'package:hl_lieferservice/feature/delivery/bloc/tour_event.dart'; import 'package:hl_lieferservice/feature/delivery/bloc/tour_state.dart'; +import 'package:hl_lieferservice/feature/delivery/util.dart'; import 'package:hl_lieferservice/model/delivery.dart'; -import '../model/sorting_information.dart'; - class CustomSortDialog extends StatefulWidget { - const CustomSortDialog({super.key}); + const CustomSortDialog({super.key, this.selectedCarId}); + + final int? selectedCarId; @override State createState() => _CustomSortDialogState(); } class _CustomSortDialogState extends State { - late List _localSortedList; + late List _localSortedList; @override void initState() { super.initState(); final state = context.read().state; if (state is TourLoaded) { - _localSortedList = [...state.sortingInformation.sorting]; - _localSortedList.sort((a, b) => a.position.compareTo(b.position)); + _localSortedList = [ + ...state.sortingInformation[widget.selectedCarId.toString()] ?? [], + ]; } else { _localSortedList = []; } } - Widget _information() { return Padding( padding: EdgeInsets.only(top: 15), @@ -68,49 +69,49 @@ class _CustomSortDialogState extends State { child: ReorderableListView( onReorder: (oldIndex, newIndex) { setState(() { - if (oldIndex < newIndex) { - newIndex -= 1; - } - final SortingInformation item = _localSortedList.removeAt(oldIndex); - _localSortedList.insert(newIndex, item); + _localSortedList = reorderList( + _localSortedList, + oldIndex, + newIndex, + ); }); context.read().add( ReorderDeliveryEvent( newPosition: newIndex, oldPosition: oldIndex, + carId: widget.selectedCarId.toString(), ), ); }, children: - _localSortedList.map((info) { - Delivery delivery = currentState.tour.deliveries.firstWhere( - (delivery) => delivery.id == info.deliveryId, - ); - SortingInformation information = currentState - .sortingInformation - .sorting - .firstWhere((info) => info.deliveryId == delivery.id); + _localSortedList + .map((id) { + Delivery delivery = currentState.tour.deliveries + .firstWhere((delivery) => delivery.id == id); + int pos = _localSortedList.indexOf(id) + 1; - return ListTile( - leading: CircleAvatar( - backgroundColor: Theme.of(context).primaryColor, - child: Text( - "${information.position + 1}", - style: TextStyle( - color: Theme.of(context).colorScheme.onSecondary, + return ListTile( + leading: CircleAvatar( + backgroundColor: Theme.of(context).primaryColor, + child: Text( + "$pos", + 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}"), - ); - }).toList(), + 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}"), + ); + }) + .toList(), ), ); } diff --git a/lib/feature/delivery/overview/presentation/delivery_overview_page.dart b/lib/feature/delivery/overview/presentation/delivery_overview_page.dart index 04487f8..0060e12 100644 --- a/lib/feature/delivery/overview/presentation/delivery_overview_page.dart +++ b/lib/feature/delivery/overview/presentation/delivery_overview_page.dart @@ -28,6 +28,8 @@ class _DeliveryOverviewPageState extends State { ); } + debugPrint(state.toString()); + return Container(); }, ); diff --git a/lib/feature/delivery/overview/service/reorder_service.dart b/lib/feature/delivery/overview/service/reorder_service.dart index d03cb04..2da20c2 100644 --- a/lib/feature/delivery/overview/service/reorder_service.dart +++ b/lib/feature/delivery/overview/service/reorder_service.dart @@ -1,17 +1,15 @@ import 'dart:convert'; import 'dart:io'; +import 'package:flutter/cupertino.dart'; import 'package:hl_lieferservice/model/tour.dart'; import 'package:path_provider/path_provider.dart'; -import '../model/sorting_information.dart'; - class ReorderService { get _path async { final dir = await getApplicationDocumentsDirectory(); final date = DateTime.now(); - final filename = - "custom_sort_${date.year}_${date.month}_${date.day}.json"; + final filename = "custom_sort_${date.year}_${date.month}_${date.day}.json"; final path = "${dir.path}/$filename"; return path; @@ -24,30 +22,53 @@ class ReorderService { return file; } - Future saveSortingInformation(SortingInformationContainer container) async { - (await _file).writeAsString(jsonEncode(container.toJson())); + Future saveSortingInformation( + Map> container, + ) async { + debugPrint("CONTAINER: ${jsonEncode(container)}"); + + (await _file).writeAsString(jsonEncode(container)); } Future initializeTour(Tour tour) async { (await _file).create(); - SortingInformationContainer container = SortingInformationContainer(sorting: []); - - for (final (index, delivery) in tour.deliveries.indexed) { - container.sorting.add( - SortingInformation(deliveryId: delivery.id, position: index), - ); + Map> sorting = {}; + + for (final delivery in tour.deliveries) { + if (!sorting.containsKey(delivery.carId.toString())) { + sorting[delivery.carId.toString()] = [delivery.id]; + } else { + sorting[delivery.carId.toString()]!.add(delivery.id); + } } - (await _file).writeAsString(jsonEncode(container.toJson())); + (await _file).writeAsString(jsonEncode({"cars": sorting})); } bool orderInformationExist() { return false; } - Future loadSortingInformation() async { - return SortingInformationContainer.fromJson( - jsonDecode(await (await _file).readAsString()), - ); + Future>> loadSortingInformation() async { + debugPrint("FILE: ${await (await _file).readAsString()}"); + Map> container = {}; + Map json = jsonDecode(await (await _file).readAsString()); + + if (!json.containsKey("cars")) { + throw Exception("No cars found in file"); + } + + for (final car in json["cars"].entries) { + List values = []; + + for (String value in car.value) { + values.add(value); + } + + container[car.key] = values; + } + + + return container; } -} \ No newline at end of file +} diff --git a/lib/feature/delivery/util.dart b/lib/feature/delivery/util.dart new file mode 100644 index 0000000..b07e0b4 --- /dev/null +++ b/lib/feature/delivery/util.dart @@ -0,0 +1,22 @@ +List reorderList(List old, int oldIndex, int newIndex) { + List tmp = [...old]; + + int newIndexCalc = newIndex - 1; + + if (newIndex < oldIndex) { + newIndexCalc = newIndex; + } + + if (newIndex == old.length) { + newIndexCalc = old.length - 1; + } + + if (newIndex == 0) { + newIndexCalc = 0; + } + + String oldItem = tmp.removeAt(oldIndex); + tmp.insert(newIndexCalc, oldItem); + + return tmp; +} diff --git a/lib/feature/scan/presentation/scan_screen.dart b/lib/feature/scan/presentation/scan_screen.dart index ffdb16e..cd0e325 100644 --- a/lib/feature/scan/presentation/scan_screen.dart +++ b/lib/feature/scan/presentation/scan_screen.dart @@ -287,6 +287,7 @@ class _ArticleScanningScreenState extends State { isExpanded: true, items: deliveries + .where((delivery) => delivery.state != DeliveryState.finished) .mapIndexed( (index, delivery) => DropdownMenuItem( value: index,