first commit

This commit is contained in:
2026-03-24 15:03:35 +01:00
commit cdba16ebe8
162 changed files with 194406 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import '../../../domain/entities/tour.dart';
import '../../../domain/entities/logistic_object.dart';
import '../../../domain/repositories/tour_repository.dart';
import '../../../core/errors/failures.dart';
part 'tour_event.dart';
part 'tour_state.dart';
class TourBloc extends Bloc<TourEvent, TourState> {
final TourRepository repository;
TourBloc({required this.repository}) : super(TourInitial()) {
on<LoadTours>(_onLoadTours);
on<SelectTour>(_onSelectTour);
on<CompleteTour>(_onCompleteTour);
on<SyncData>(_onSyncData);
on<RefreshTours>(_onRefreshTours);
on<LoadTourDetails>(_onLoadTourDetails);
}
Future<void> _onLoadTours(LoadTours event, Emitter<TourState> emit) async {
emit(TourLoading());
final result = await repository.getTours();
result.fold(
(failure) => emit(TourError(message: _mapFailureToMessage(failure))),
(tours) {
final openTours = tours.where((t) => t.state < 2).toList();
final completedTours = tours.where((t) => t.state == 1).toList();
emit(ToursLoaded(
tours: openTours,
completedTours: completedTours,
allTours: tours,
));
},
);
}
Future<void> _onSelectTour(SelectTour event, Emitter<TourState> emit) async {
final currentState = state;
if (currentState is ToursLoaded) {
emit(currentState.copyWith(selectedTour: event.tour));
}
}
Future<void> _onCompleteTour(CompleteTour event, Emitter<TourState> emit) async {
final currentState = state;
if (currentState is ToursLoaded) {
emit(TourLoading());
final result = await repository.completeTour(event.tourId);
result.fold(
(failure) => emit(TourError(message: _mapFailureToMessage(failure))),
(_) => add(const LoadTours()),
);
}
}
Future<void> _onSyncData(SyncData event, Emitter<TourState> emit) async {
final currentState = state;
if (currentState is ToursLoaded) {
emit(currentState.copyWith(isSyncing: true));
final result = await repository.syncData();
result.fold(
(failure) {
emit(currentState.copyWith(isSyncing: false));
emit(SyncError(message: _mapFailureToMessage(failure)));
},
(_) {
emit(currentState.copyWith(isSyncing: false));
add(const LoadTours());
},
);
}
}
Future<void> _onRefreshTours(RefreshTours event, Emitter<TourState> emit) async {
add(const LoadTours());
}
Future<void> _onLoadTourDetails(LoadTourDetails event, Emitter<TourState> emit) async {
final currentState = state;
if (currentState is ToursLoaded) {
emit(currentState.copyWith(isLoadingDetails: true));
final objectsResult = await repository.getObjectsByTour(event.tourId);
final statsResult = await repository.getTourStatistics(event.tourId);
objectsResult.fold(
(failure) => emit(TourError(message: _mapFailureToMessage(failure))),
(objects) {
statsResult.fold(
(failure) => emit(TourError(message: _mapFailureToMessage(failure))),
(statistics) {
emit(currentState.copyWith(
selectedTourObjects: objects,
selectedTourStats: statistics,
isLoadingDetails: false,
));
},
);
},
);
}
}
String _mapFailureToMessage(Failure failure) {
return switch (failure) {
ServerFailure _ => 'Serverfehler: ${failure.message}',
NetworkFailure _ => 'Netzwerkfehler. Bitte überprüfen Sie Ihre Internetverbindung.',
CacheFailure _ => 'Cachefehler: ${failure.message}',
NotFoundFailure _ => 'Daten nicht gefunden',
UnauthorizedFailure _ => 'Nicht autorisiert. Bitte melden Sie sich erneut an.',
_ => 'Ein unerwarteter Fehler ist aufgetreten',
};
}
}

View File

@@ -0,0 +1,56 @@
part of 'tour_bloc.dart';
abstract class TourEvent extends Equatable {
const TourEvent();
@override
List<Object?> get props => [];
}
class LoadTours extends TourEvent {
const LoadTours();
}
class SelectTour extends TourEvent {
final Tour tour;
const SelectTour(this.tour);
@override
List<Object?> get props => [tour];
}
class CompleteTour extends TourEvent {
final int tourId;
const CompleteTour(this.tourId);
@override
List<Object?> get props => [tourId];
}
class SyncData extends TourEvent {
const SyncData();
}
class RefreshTours extends TourEvent {
const RefreshTours();
}
class LoadTourDetails extends TourEvent {
final int tourId;
const LoadTourDetails(this.tourId);
@override
List<Object?> get props => [tourId];
}
class UpdateShowCompleted extends TourEvent {
final bool showCompleted;
const UpdateShowCompleted(this.showCompleted);
@override
List<Object?> get props => [showCompleted];
}

View File

@@ -0,0 +1,95 @@
part of 'tour_bloc.dart';
abstract class TourState extends Equatable {
const TourState();
@override
List<Object?> get props => [];
}
class TourInitial extends TourState {}
class TourLoading extends TourState {}
class ToursLoaded extends TourState {
final List<Tour> tours;
final List<Tour> completedTours;
final List<Tour> allTours;
final Tour? selectedTour;
final List<LogisticObject>? selectedTourObjects;
final TourStatistics? selectedTourStats;
final bool isSyncing;
final bool isLoadingDetails;
final bool showCompleted;
const ToursLoaded({
required this.tours,
this.completedTours = const [],
required this.allTours,
this.selectedTour,
this.selectedTourObjects,
this.selectedTourStats,
this.isSyncing = false,
this.isLoadingDetails = false,
this.showCompleted = true,
});
ToursLoaded copyWith({
List<Tour>? tours,
List<Tour>? completedTours,
List<Tour>? allTours,
Tour? selectedTour,
List<LogisticObject>? selectedTourObjects,
TourStatistics? selectedTourStats,
bool? isSyncing,
bool? isLoadingDetails,
bool? showCompleted,
}) {
return ToursLoaded(
tours: tours ?? this.tours,
completedTours: completedTours ?? this.completedTours,
allTours: allTours ?? this.allTours,
selectedTour: selectedTour ?? this.selectedTour,
selectedTourObjects: selectedTourObjects ?? this.selectedTourObjects,
selectedTourStats: selectedTourStats ?? this.selectedTourStats,
isSyncing: isSyncing ?? this.isSyncing,
isLoadingDetails: isLoadingDetails ?? this.isLoadingDetails,
showCompleted: showCompleted ?? this.showCompleted,
);
}
int get completedCount => completedTours.length;
int get totalCount => allTours.length;
double get completionPercentage => totalCount > 0 ? (completedCount / totalCount) * 100 : 0;
@override
List<Object?> get props => [
tours,
completedTours,
allTours,
selectedTour,
selectedTourObjects,
selectedTourStats,
isSyncing,
isLoadingDetails,
showCompleted,
];
}
class TourError extends TourState {
final String message;
const TourError({required this.message});
@override
List<Object?> get props => [message];
}
class SyncError extends TourState {
final String message;
const SyncError({required this.message});
@override
List<Object?> get props => [message];
}