Implemented new set article mechanism for unscannable articles

This commit is contained in:
Dennis Nemec
2026-01-10 20:20:28 +01:00
parent 1848f47e7f
commit 2436177c95
17 changed files with 334 additions and 46 deletions

View File

@ -14,3 +14,7 @@ A few resources to get you started if this is your first Flutter project:
For help getting started with Flutter development, view the For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials, [online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference. samples, guidance on mobile development, and a full API reference.
## JSON code generation
use `dart run build_runner watch --delete-conflicting-outputs` for generating

View File

@ -0,0 +1,23 @@
import 'package:json_annotation/json_annotation.dart';
part 'set_article_amount_request.g.dart';
@JsonSerializable(fieldRename: FieldRename.snake)
class SetArticleAmountRequestDTO {
SetArticleAmountRequestDTO({
required this.articleId,
required this.deliveryId,
required this.amount,
this.reason
});
String deliveryId;
int amount;
String articleId;
String? reason;
factory SetArticleAmountRequestDTO.fromJson(Map<String, dynamic> json) =>
_$SetArticleAmountRequestDTOFromJson(json);
Map<dynamic, dynamic> toJson() => _$SetArticleAmountRequestDTOToJson(this);
}

View File

@ -0,0 +1,21 @@
import 'package:hl_lieferservice/dto/basic_response.dart';
import 'package:json_annotation/json_annotation.dart';
part 'set_article_amount_response.g.dart';
@JsonSerializable(fieldRename: FieldRename.snake)
class SetArticleAmountResponseDTO extends BasicResponseDTO {
SetArticleAmountResponseDTO({
required super.succeeded,
required super.message,
this.noteId
});
String? noteId;
factory SetArticleAmountResponseDTO.fromJson(Map<String, dynamic> json) =>
_$SetArticleAmountResponseDTOFromJson(json);
@override
Map<dynamic, dynamic> toJson() => _$SetArticleAmountResponseDTOToJson(this);
}

View File

@ -5,7 +5,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/tour_event.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/bloc/tour_state.dart';
import 'package:hl_lieferservice/feature/delivery/overview/model/sorting_information.dart'; import 'package:hl_lieferservice/feature/delivery/overview/model/sorting_information.dart';
import 'package:hl_lieferservice/feature/delivery/overview/repository/tour_repository.dart'; 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/distance_service.dart';
import 'package:hl_lieferservice/feature/delivery/overview/service/reorder_service.dart'; import 'package:hl_lieferservice/feature/delivery/overview/service/reorder_service.dart';
import 'package:hl_lieferservice/model/tour.dart'; import 'package:hl_lieferservice/model/tour.dart';
@ -55,6 +55,7 @@ class TourBloc extends Bloc<TourEvent, TourState> {
on<RequestSortingInformationEvent>(_requestSortingInformation); on<RequestSortingInformationEvent>(_requestSortingInformation);
on<ReorderDeliveryEvent>(_reorderDelivery); on<ReorderDeliveryEvent>(_reorderDelivery);
on<CarsLoadedEvent>(_carsLoaded); on<CarsLoadedEvent>(_carsLoaded);
on<SetArticleAmountEvent>(_setArticleAmount);
} }
@override @override
@ -64,6 +65,33 @@ class TourBloc extends Bloc<TourEvent, TourState> {
return super.close(); return super.close();
} }
void _setArticleAmount(
SetArticleAmountEvent event,
Emitter<TourState> emit,
) async {
final currentState = state;
if (currentState is TourLoaded) {
opBloc.add(LoadOperation());
try {
await tourRepository.setArticleAmount(
event.deliveryId,
event.articleId,
event.amount,
event.reason
);
opBloc.add(FinishOperation());
} catch (e, st) {
opBloc.add(
FailOperation(message: "Fehler beim Ändern der Menge des Artikels"),
);
debugPrint("$e");
debugPrint("$st");
}
}
}
void _carsLoaded(CarsLoadedEvent event, Emitter<TourState> emit) { void _carsLoaded(CarsLoadedEvent event, Emitter<TourState> emit) {
final currentState = state; final currentState = state;
if (currentState is TourLoaded) { if (currentState is TourLoaded) {
@ -78,13 +106,16 @@ class TourBloc extends Bloc<TourEvent, TourState> {
) async { ) async {
final currentState = state; final currentState = state;
if (currentState is TourLoaded) { if (currentState is TourLoaded) {
int newPosition = event.newPosition == currentState.sortingInformation.sorting.length ? event.newPosition - 1 : event.newPosition; int newPosition =
SortingInformation informationOld = currentState.sortingInformation.sorting event.newPosition == currentState.sortingInformation.sorting.length
.firstWhere((info) => info.position == event.oldPosition); ? event.newPosition - 1
: event.newPosition;
SortingInformation information = currentState SortingInformation informationOld = currentState
.sortingInformation .sortingInformation
.sorting .sorting
.firstWhere((info) => info.position == event.oldPosition);
SortingInformation information = currentState.sortingInformation.sorting
.firstWhere((info) => info.position == newPosition); .firstWhere((info) => info.position == newPosition);
information.position = event.oldPosition; information.position = event.oldPosition;

View File

@ -203,3 +203,17 @@ class FinishDeliveryEvent extends TourEvent {
Uint8List customerSignature; Uint8List customerSignature;
Uint8List driverSignature; Uint8List driverSignature;
} }
class SetArticleAmountEvent extends TourEvent {
final String deliveryId;
final String articleId;
final String? reason;
final int amount;
SetArticleAmountEvent({
required this.deliveryId,
required this.articleId,
required this.amount,
this.reason,
});
}

View File

@ -23,6 +23,10 @@ class _ArticleListItem extends State<ArticleListItem> {
Color? color; Color? color;
Color? textColor; Color? textColor;
if (!widget.article.scannable) {
amount = widget.article.amount;
}
if (amount == 0) { if (amount == 0) {
color = Colors.redAccent; color = Colors.redAccent;
textColor = Theme.of(context).colorScheme.onSecondary; textColor = Theme.of(context).colorScheme.onSecondary;
@ -56,7 +60,8 @@ class _ArticleListItem extends State<ArticleListItem> {
), ),
); );
if (widget.article.unscanned()) { if ((widget.article.unscanned() && widget.article.scannable) ||
!widget.article.scannable && widget.article.amount == 0) {
actionButton = IconButton.outlined( actionButton = IconButton.outlined(
style: ButtonStyle( style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll(Colors.blueAccent), backgroundColor: WidgetStatePropertyAll(Colors.blueAccent),

View File

@ -20,33 +20,86 @@ class ResetArticleAmountDialog extends StatefulWidget {
} }
class _ResetArticleAmountDialogState extends State<ResetArticleAmountDialog> { class _ResetArticleAmountDialogState extends State<ResetArticleAmountDialog> {
int _selectedAmount = 1;
void _reset() { void _reset() {
context.read<TourBloc>().add( String deliveryId = widget.deliveryId;
ResetScanAmountEvent( String articleId = widget.article.internalId.toString();
articleId: widget.article.internalId.toString(),
deliveryId: widget.deliveryId, if (widget.article.scannable) {
), context.read<TourBloc>().add(
); ResetScanAmountEvent(
articleId: widget.article.internalId.toString(),
deliveryId: widget.deliveryId,
),
);
} else {
debugPrint("ID: $articleId");
debugPrint("AMOUNT :$_selectedAmount");
context.read<TourBloc>().add(
SetArticleAmountEvent(
deliveryId: deliveryId,
articleId: articleId,
amount: _selectedAmount,
),
);
}
Navigator.pop(context); Navigator.pop(context);
} }
Widget _amountSelection() {
final list = List.generate(3, (index) => index + 1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Anzahl:", style: Theme.of(context).textTheme.labelLarge),
Padding(
padding: const EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:
list
.map(
(index) => ChoiceChip(
label: Text("$index"),
selected: _selectedAmount == index,
onSelected: (bool selected) {
setState(() {
_selectedAmount = index;
});
},
),
)
.toList(),
),
),
],
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
title: const Text("Anzahl Artikel zurücksetzen?"), title: const Text("Anzahl Artikel zurücksetzen?"),
content: SizedBox( content: SizedBox(
height: 120, height: MediaQuery.of(context).size.height * 0.25,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Text("Wollen Sie die entfernten Artikel wieder hinzufügen?"), const Text("Wollen Sie die entfernten Artikel wieder hinzufügen?"),
!widget.article.scannable ? _amountSelection() : Container(),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
FilledButton( FilledButton(
onPressed: _reset, onPressed: _reset,
child: const Text("Zurücksetzen"), child:
widget.article.scannable
? const Text("Zurücksetzen")
: const Text("Hinzufügen"),
), ),
OutlinedButton( OutlinedButton(
onPressed: () { onPressed: () {

View File

@ -7,7 +7,11 @@ import 'package:hl_lieferservice/feature/delivery/bloc/tour_event.dart';
import '../../../../../model/article.dart'; import '../../../../../model/article.dart';
class ArticleUnscanDialog extends StatefulWidget { class ArticleUnscanDialog extends StatefulWidget {
const ArticleUnscanDialog({super.key, required this.article, required this.deliveryId}); const ArticleUnscanDialog({
super.key,
required this.article,
required this.deliveryId,
});
final String deliveryId; final String deliveryId;
final Article article; final Article article;
@ -23,14 +27,32 @@ class _ArticleUnscanDialogState extends State<ArticleUnscanDialog> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
void _unscan() { void _unscan() {
context.read<TourBloc>().add( int amountToBeDeleted = int.parse(unscanAmountController.text);
UnscanArticleEvent( String deliveryId = widget.deliveryId;
deliveryId: widget.deliveryId, String articleId = widget.article.internalId.toString();
articleId: widget.article.internalId.toString(), String reason = unscanNoteController.text;
newAmount: int.parse(unscanAmountController.text),
reason: unscanNoteController.text, if (widget.article.scannable) {
), context.read<TourBloc>().add(
); UnscanArticleEvent(
deliveryId: deliveryId,
articleId: articleId,
newAmount: amountToBeDeleted,
reason: reason,
),
);
} else {
// If the article is not scannable we need to adjust the quantity of the article
// directly.
context.read<TourBloc>().add(
SetArticleAmountEvent(
deliveryId: deliveryId,
articleId: articleId,
amount: widget.article.amount - amountToBeDeleted,
reason: reason
),
);
}
Navigator.pop(context); Navigator.pop(context);
} }

View File

@ -136,6 +136,9 @@ class _DeliveryDetailState extends State<DeliveryDetail> {
driverSignature: driver, driverSignature: driver,
), ),
); );
Navigator.pop(context);
Navigator.pop(context);
} }
Widget _stepsNavigation(Delivery delivery) { Widget _stepsNavigation(Delivery delivery) {

View File

@ -117,8 +117,6 @@ class _SignatureViewState extends State<SignatureView> {
builder: (context, state) { builder: (context, state) {
final current = state; final current = state;
debugPrint("STATE: $current");
if (current is NoteLoaded) { if (current is NoteLoaded) {
if (current.notes.isEmpty) { if (current.notes.isEmpty) {
return const SizedBox( return const SizedBox(

View File

@ -5,7 +5,7 @@ import 'package:hl_lieferservice/dto/discount_remove_response.dart';
import 'package:hl_lieferservice/dto/discount_update_response.dart'; import 'package:hl_lieferservice/dto/discount_update_response.dart';
import 'package:hl_lieferservice/feature/delivery/detail/repository/note_repository.dart'; import 'package:hl_lieferservice/feature/delivery/detail/repository/note_repository.dart';
import 'package:hl_lieferservice/feature/delivery/detail/service/notes_service.dart'; import 'package:hl_lieferservice/feature/delivery/detail/service/notes_service.dart';
import 'package:hl_lieferservice/feature/delivery/overview/service/delivery_info_service.dart'; import 'package:hl_lieferservice/feature/delivery/service/tour_service.dart';
import 'package:hl_lieferservice/model/delivery.dart'; import 'package:hl_lieferservice/model/delivery.dart';
class DeliveryRepository { class DeliveryRepository {

View File

@ -60,7 +60,7 @@ class _DeliveryListState extends State<DeliveryList> {
.where( .where(
(delivery) => (delivery) =>
delivery.carId == widget.selectedCarId && delivery.carId == widget.selectedCarId &&
delivery.allArticlesScanned(), delivery.allArticlesScanned() || delivery.state == DeliveryState.finished,
) )
.toList(); .toList();

View File

@ -1,6 +1,7 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:hl_lieferservice/feature/delivery/overview/service/delivery_info_service.dart'; import 'package:hl_lieferservice/dto/set_article_amount_response.dart';
import 'package:hl_lieferservice/feature/delivery/service/tour_service.dart';
import 'package:hl_lieferservice/model/delivery.dart'; import 'package:hl_lieferservice/model/delivery.dart';
import 'package:hl_lieferservice/model/tour.dart'; import 'package:hl_lieferservice/model/tour.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
@ -9,8 +10,8 @@ import '../../../../dto/discount_add_response.dart';
import '../../../../dto/discount_remove_response.dart'; import '../../../../dto/discount_remove_response.dart';
import '../../../../dto/discount_update_response.dart'; import '../../../../dto/discount_update_response.dart';
import '../../../../model/article.dart'; import '../../../../model/article.dart';
import '../../detail/repository/note_repository.dart'; import '../detail/repository/note_repository.dart';
import '../../detail/service/notes_service.dart'; import '../detail/service/notes_service.dart';
enum ScanResult { scanned, alreadyScanned, notFound } enum ScanResult { scanned, alreadyScanned, notFound }
@ -172,13 +173,19 @@ class TourRepository {
Delivery delivery = tour.deliveries.firstWhere( Delivery delivery = tour.deliveries.firstWhere(
(delivery) => delivery.id == deliveryId, (delivery) => delivery.id == deliveryId,
); );
Article discountArticle = Article.fromDTO(response.values.article);
delivery.totalNetValue = response.values.receipt.net; delivery.totalNetValue = response.values.receipt.net;
delivery.totalGrossValue = response.values.receipt.gross; delivery.totalGrossValue = response.values.receipt.gross;
delivery.discount = Discount( delivery.discount = Discount(
article: Article.fromDTO(response.values.article), article: Article.fromDTO(response.values.article),
note: response.values.note.noteDescription, note: response.values.note.noteDescription,
noteId: response.values.note.rowId, noteId: response.values.note.rowId,
); );
delivery.articles = [
...delivery.articles,
discountArticle,
];
_tourStream.add(tour); _tourStream.add(tour);
} }
@ -275,6 +282,45 @@ class TourRepository {
Future<void> finishDelivery(String deliveryId) async { Future<void> finishDelivery(String deliveryId) async {
await _changeState(deliveryId, DeliveryState.finished); await _changeState(deliveryId, DeliveryState.finished);
Delivery delivery = _tourStream.value!.deliveries.firstWhere(
(delivery) => delivery.id == deliveryId,
);
await _updateDelivery(delivery);
await service.finishDelivery(deliveryId);
}
Future<void> setArticleAmount(
String deliveryId,
String articleId,
int amount,
String? reason,
) async {
if (!_tourStream.hasValue) {
throw TourNotFoundException();
}
try {
SetArticleAmountResponseDTO dto = await service.setArticleAmount(
deliveryId,
articleId,
amount,
reason,
);
Delivery delivery = _tourStream.value!.deliveries.firstWhere(
(delivery) => delivery.id == deliveryId,
);
Article article = delivery.articles.firstWhere(
(article) => article.internalId == int.parse(articleId),
);
article.amount = amount;
article.removeNoteId = dto.noteId;
_tourStream.add(_tourStream.value);
} catch (_) {
rethrow;
}
} }
Future<void> _changeState(String deliveryId, DeliveryState state) async { Future<void> _changeState(String deliveryId, DeliveryState state) async {

View File

@ -7,18 +7,20 @@ import 'package:hl_lieferservice/dto/delivery_update.dart';
import 'package:hl_lieferservice/dto/delivery_update_response.dart'; import 'package:hl_lieferservice/dto/delivery_update_response.dart';
import 'package:hl_lieferservice/dto/payment.dart'; import 'package:hl_lieferservice/dto/payment.dart';
import 'package:hl_lieferservice/dto/payments.dart'; import 'package:hl_lieferservice/dto/payments.dart';
import 'package:hl_lieferservice/dto/set_article_amount_request.dart';
import 'package:hl_lieferservice/dto/set_article_amount_response.dart';
import 'package:hl_lieferservice/model/car.dart'; import 'package:hl_lieferservice/model/car.dart';
import 'package:hl_lieferservice/model/delivery.dart'; import 'package:hl_lieferservice/model/delivery.dart';
import 'package:hl_lieferservice/model/tour.dart'; import 'package:hl_lieferservice/model/tour.dart';
import 'package:hl_lieferservice/util.dart'; import 'package:hl_lieferservice/util.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import '../../../../dto/basic_response.dart'; import '../../../dto/basic_response.dart';
import '../../../../dto/discount_add_response.dart'; import '../../../dto/discount_add_response.dart';
import '../../../../dto/discount_remove_response.dart'; import '../../../dto/discount_remove_response.dart';
import '../../../../dto/discount_update_response.dart'; import '../../../dto/discount_update_response.dart';
import '../../../../dto/scan_response.dart'; import '../../../dto/scan_response.dart';
import '../../../authentication/exceptions.dart'; import '../../authentication/exceptions.dart';
class TourService { class TourService {
TourService(); TourService();
@ -267,6 +269,76 @@ class TourService {
} }
} }
Future<BasicResponseDTO> finishDelivery(String deliveryId) async {
try {
var response = await post(
urlBuilder("_web_finishDelivery"),
headers: getSessionOrThrow(),
body: {"delivery_id": deliveryId},
);
if (response.statusCode == HttpStatus.unauthorized) {
throw UserUnauthorized();
}
debugPrint("BODY: ${response.body}");
Map<String, dynamic> responseJson = jsonDecode(response.body);
// let it throw, if the values are invalid
return BasicResponseDTO.fromJson(responseJson);
} catch (e, st) {
debugPrint("ERROR while adding discount");
debugPrint(e.toString());
debugPrint(st.toString());
rethrow;
}
}
Future<SetArticleAmountResponseDTO> setArticleAmount(
String deliveryId,
String articleId,
int amount,
String? reason,
) async {
try {
var response = await post(
urlBuilder("_web_setArticleAmount"),
headers: {...getSessionOrThrow(), "Content-Type": "application/json"},
body: jsonEncode(
SetArticleAmountRequestDTO(
articleId: articleId,
deliveryId: deliveryId,
amount: amount,
reason: reason,
),
),
);
if (response.statusCode == HttpStatus.unauthorized) {
throw UserUnauthorized();
}
debugPrint("BODY: ${response.body}");
Map<String, dynamic> responseJson = jsonDecode(response.body);
// let it throw, if the values are invalid
SetArticleAmountResponseDTO responseDto =
SetArticleAmountResponseDTO.fromJson(responseJson);
if (!responseDto.succeeded) {
throw responseDto.message;
} else {
return responseDto;
}
} catch (e, st) {
debugPrint(e.toString());
debugPrint(st.toString());
rethrow;
}
}
Future<DiscountRemoveResponseDTO> removeDiscount(String deliveryId) async { Future<DiscountRemoveResponseDTO> removeDiscount(String deliveryId) async {
try { try {
var response = await post( var response = await post(

View File

@ -3,6 +3,7 @@ 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_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/tour_state.dart'; import 'package:hl_lieferservice/feature/delivery/bloc/tour_state.dart';
import 'package:hl_lieferservice/feature/scan/presentation/scan_screen.dart'; import 'package:hl_lieferservice/feature/scan/presentation/scan_screen.dart';
import 'package:hl_lieferservice/model/delivery.dart';
import 'package:hl_lieferservice/model/tour.dart'; import 'package:hl_lieferservice/model/tour.dart';
import 'package:hl_lieferservice/widget/home/bloc/navigation_bloc.dart'; import 'package:hl_lieferservice/widget/home/bloc/navigation_bloc.dart';
import 'package:hl_lieferservice/widget/home/bloc/navigation_event.dart'; import 'package:hl_lieferservice/widget/home/bloc/navigation_event.dart';
@ -36,7 +37,7 @@ class _ScanPageState extends State<ScanPage> {
Widget _tourSteps(Tour tour) { Widget _tourSteps(Tour tour) {
var allArticlesScanned = tour.deliveries.every( var allArticlesScanned = tour.deliveries.every(
(delivery) => delivery.allArticlesScanned(), (delivery) => delivery.allArticlesScanned() || delivery.state == DeliveryState.finished,
); );
return Stepper( return Stepper(

View File

@ -1,6 +1,5 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:hl_lieferservice/dto/contact_person.dart'; import 'package:hl_lieferservice/dto/contact_person.dart';
import 'package:hl_lieferservice/dto/delivery.dart'; import 'package:hl_lieferservice/dto/delivery.dart';
import 'package:hl_lieferservice/dto/image_note_response.dart'; import 'package:hl_lieferservice/dto/image_note_response.dart';
@ -297,11 +296,7 @@ class Delivery implements Comparable<Delivery> {
List<Article> getDeliveredArticles() { List<Article> getDeliveredArticles() {
return articles return articles
.where( .where(
(article) { (article) => article.scannedAmount > 0 || !article.scannable,
debugPrint("Scannable: ${article.scannable}");
return article.scannedAmount > 0 || !article.scannable;
},
) )
.toList(); .toList();
} }

View File

@ -6,13 +6,13 @@ import 'package:hl_lieferservice/feature/authentication/presentation/login_enfor
import 'package:hl_lieferservice/feature/authentication/service/userinfo.dart'; import 'package:hl_lieferservice/feature/authentication/service/userinfo.dart';
import 'package:hl_lieferservice/feature/cars/presentation/car_management_page.dart'; import 'package:hl_lieferservice/feature/cars/presentation/car_management_page.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/tour_bloc.dart'; import 'package:hl_lieferservice/feature/delivery/bloc/tour_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/repository/tour_repository.dart'; import 'package:hl_lieferservice/feature/delivery/repository/tour_repository.dart';
import 'package:hl_lieferservice/widget/home/bloc/navigation_bloc.dart'; import 'package:hl_lieferservice/widget/home/bloc/navigation_bloc.dart';
import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart'; import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart';
import 'package:hl_lieferservice/widget/operations/presentation/operation_view_enforcer.dart'; import 'package:hl_lieferservice/widget/operations/presentation/operation_view_enforcer.dart';
import 'package:hl_lieferservice/bloc/app_states.dart'; import 'package:hl_lieferservice/bloc/app_states.dart';
import '../feature/delivery/overview/service/delivery_info_service.dart'; import '../feature/delivery/service/tour_service.dart';
import 'home/presentation/home.dart'; import 'home/presentation/home.dart';
class DeliveryApp extends StatefulWidget { class DeliveryApp extends StatefulWidget {