import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_event.dart'; import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_state.dart'; import 'package:hl_lieferservice/feature/delivery/overview/repository/tour_repository.dart'; import 'package:hl_lieferservice/feature/delivery/overview/service/distance_service.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'; import 'package:rxdart/rxdart.dart'; class TourBloc extends Bloc { OperationBloc opBloc; TourRepository tourRepository; StreamSubscription? _combinedSubscription; TourBloc({required this.opBloc, required this.tourRepository}) : super(TourInitial()) { _combinedSubscription = CombineLatestStream.combine2( tourRepository.tour, tourRepository.paymentOptions, (tour, payments) => {'tour': tour, 'payments': payments}, ).listen((combined) { final tour = combined['tour'] as Tour?; final payments = combined['payments'] as List; if (tour == null) { return; } add(TourUpdated(tour: tour, payments: payments)); }); on(_load); on(_assignCar); on(_increment); on(_scan); on(_holdDelivery); on(_cancelDelivery); on(_reactivateDelivery); on(_unscan); on(_resetAmount); on(_addDiscount); on(_removeDiscount); on(_updateDiscount); on(_updateDeliveryOptions); on(_updatePayment); on(_finishDelivery); on(_updated); on(_calculateDistances); } @override Future close() { _combinedSubscription?.cancel(); return super.close(); } void _calculateDistances( RequestDeliveryDistanceEvent event, Emitter emit, ) async { Map distances = {}; opBloc.add(LoadOperation()); emit(TourRequestingDistances(tour: event.tour, payments: event.payments)); try { for (final delivery in event.tour.deliveries) { distances[delivery.id] = await DistanceService.getDistanceByRoad( delivery.customer.address.toString(), ); } opBloc.add(FinishOperation()); } catch (e) { debugPrint("Fehler beim Berechnen der Distanzen: $e"); opBloc.add(FailOperation(message: "Fehler beim Berechnen der Distanzen")); return; } emit( TourLoaded( tour: event.tour, paymentOptions: event.payments, distances: distances, ), ); } void _updated(TourUpdated event, Emitter emit) { final currentState = state; final tour = event.tour.copyWith(); final payments = event.payments.map((payment) => payment.copyWith()).toList(); if (currentState is TourLoaded) { debugPrint("TEST UPDATE"); emit( TourLoaded( tour: tour, paymentOptions: payments, distances: Map.from(currentState.distances ?? {}), ), ); } if (currentState is TourLoading) { add( RequestDeliveryDistanceEvent(tour: tour.copyWith(), payments: payments), ); } } void _reactivateDelivery( ReactivateDeliveryEvent event, Emitter emit, ) async { final currentState = state; if (currentState is TourLoaded) { opBloc.add(LoadOperation()); try { await tourRepository.reactivateDelivery(event.deliveryId); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint("$e"); debugPrint("$st"); opBloc.add( FailOperation(message: "Fehler beim Zurückstellen der Lieferung"), ); } } } void _holdDelivery(HoldDeliveryEvent event, Emitter emit) async { final currentState = state; if (currentState is TourLoaded) { opBloc.add(LoadOperation()); try { await tourRepository.holdDelivery(event.deliveryId); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint("$e"); debugPrint("$st"); opBloc.add( FailOperation(message: "Fehler beim Zurückstellen der Lieferung"), ); } } } void _cancelDelivery( CancelDeliveryEvent event, Emitter emit, ) async { final currentState = state; if (currentState is TourLoaded) { opBloc.add(LoadOperation()); try { await tourRepository.cancelDelivery(event.deliveryId); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint("$e"); debugPrint("$st"); opBloc.add( FailOperation(message: "Fehler beim Zurückstellen der Lieferung"), ); } } } void _scan(ScanArticleEvent event, Emitter emit) async { final currentState = state; opBloc.add(LoadOperation()); if (currentState is TourLoaded) { try { switch (await tourRepository.scanArticle( event.deliveryId, event.carId, event.articleNumber, )) { case ScanResult.scanned: opBloc.add(FinishOperation(message: 'Artikel gescannt')); break; case ScanResult.alreadyScanned: opBloc.add( FailOperation(message: 'Artikel wurde bereits gescannt'), ); break; case ScanResult.notFound: opBloc.add( FailOperation( message: 'Artikel ist für keine Lieferung vorgesehen', ), ); break; } } on TourNotFoundException catch (e) { opBloc.add(FailOperation(message: "Fehler beim Scannen des Artikels")); } } } Future _increment( IncrementArticleScanAmount event, Emitter emit, ) async { final currentState = state; if (currentState is TourLoaded) { opBloc.add(LoadOperation()); try { await tourRepository.scanArticle( event.deliveryId, event.carId, event.internalArticleId, ); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint(st.toString()); opBloc.add(FailOperation(message: "Fehler beim Scannen des Artikels")); } } } Future _assignCar(AssignCarEvent event, Emitter emit) async { final currentState = state; if (currentState is TourLoaded) { opBloc.add(LoadOperation()); try { await tourRepository.assignCar(event.deliveryId, event.carId); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint(st.toString()); opBloc.add( FailOperation(message: "Fehler beim Zuweisen des Fahrzeugs"), ); } } } Future _load(LoadTour event, Emitter emit) async { opBloc.add(LoadOperation()); try { emit(TourLoading()); await tourRepository.loadTourOfToday(event.teamId); await tourRepository.loadPaymentOptions(); opBloc.add(FinishOperation()); } catch (e) { opBloc.add( FailOperation(message: "Fehler beim Laden der heutigen Fahrten"), ); } } void _finishDelivery( FinishDeliveryEvent event, Emitter emit, ) async { final currentState = state; opBloc.add(LoadOperation()); if (currentState is TourLoaded) { try { await tourRepository.uploadDriverSignature( event.deliveryId, event.driverSignature, ); await tourRepository.uploadCustomerSignature( event.deliveryId, event.customerSignature, ); await tourRepository.finishDelivery(event.deliveryId); opBloc.add(FinishOperation()); } catch (e, st) { opBloc.add(FailOperation(message: "Failed to update delivery")); debugPrint(st.toString()); } } } void _updatePayment( UpdateSelectedPaymentMethodEvent event, Emitter emit, ) async { try { opBloc.add(LoadOperation()); await tourRepository.updatePayment(event.deliveryId, event.payment); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint(st.toString()); opBloc.add( FailOperation(message: "Fehler beim Aktualisieren des Betrags"), ); } } void _updateDeliveryOptions( UpdateDeliveryOptionEvent event, Emitter emit, ) async { try { opBloc.add(LoadOperation()); await tourRepository.updateOption( event.deliveryId, event.key, event.value, ); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint("$st"); opBloc.add( FailOperation(message: "Fehler beim Aktualisieren der Optionen"), ); } } void _updateDiscount( UpdateDiscountEvent event, Emitter emit, ) async { opBloc.add(LoadOperation()); try { opBloc.add(FinishOperation()); await tourRepository.updateDiscount( event.deliveryId, event.reason, event.value, ); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint( "Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event.deliveryId}:", ); debugPrint("$e"); debugPrint("$st"); opBloc.add( FailOperation(message: "Fehler beim Hinzufügen des Discounts: $e"), ); } } void _removeDiscount( RemoveDiscountEvent event, Emitter emit, ) async { opBloc.add(LoadOperation()); try { await tourRepository.removeDiscount(event.deliveryId); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint( "Fehler beim Löschen des Discounts der Lieferung: ${event.deliveryId}:", ); debugPrint("$e"); debugPrint("$st"); opBloc.add( FailOperation(message: "Fehler beim Löschen des Discounts: $e"), ); } } void _addDiscount(AddDiscountEvent event, Emitter emit) async { opBloc.add(LoadOperation()); try { await tourRepository.addDiscount( event.deliveryId, event.reason, event.value, ); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint( "Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event.deliveryId}:", ); debugPrint("$e"); debugPrint("$st"); opBloc.add( FailOperation(message: "Fehler beim Hinzufügen des Discounts: $e"), ); } } void _unscan(UnscanArticleEvent event, Emitter emit) async { opBloc.add(LoadOperation()); try { await tourRepository.unscan( event.deliveryId, event.articleId, event.newAmount, event.reason, ); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint("Fehler beim Unscan des Artikels: ${event.articleId}:"); debugPrint("$e"); debugPrint("$st"); opBloc.add(FailOperation(message: "Fehler beim Unscan des Artikels: $e")); } } void _resetAmount(ResetScanAmountEvent event, Emitter emit) async { opBloc.add(LoadOperation()); try { await tourRepository.resetScan(event.articleId, event.deliveryId); opBloc.add(FinishOperation()); } catch (e, st) { debugPrint("Fehler beim Unscan des Artikels: ${event.articleId}:"); debugPrint("$e"); debugPrint("$st"); opBloc.add(FailOperation(message: "Fehler beim Zurücksetzen: $e")); } } }