Initial draft

This commit is contained in:
Dennis Nemec
2025-09-20 16:14:06 +02:00
commit b19a6e1cd4
219 changed files with 10317 additions and 0 deletions

View File

@ -0,0 +1,81 @@
import 'package:flutter/material.dart';
import 'package:hl_lieferservice/model/tour.dart';
import 'package:intl/intl.dart';
class DeliveryInfo extends StatelessWidget {
final Tour tour;
const DeliveryInfo({super.key, required this.tour});
@override
Widget build(BuildContext context) {
String date = DateFormat("dd.MM.yyyy").format(tour.date);
String amountDeliveries = tour.deliveries.length.toString();
return Padding(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Text(
"Informationen",
style: Theme.of(context).textTheme.headlineSmall,
),
),
SizedBox(
width: double.infinity,
child: Card(
color: Theme.of(context).colorScheme.onSecondary,
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(Icons.calendar_month),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text("Datum"),
),
],
),
Text(date),
],
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(Icons.local_shipping_outlined),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text("Lieferungen"),
),
],
),
Text(amountDeliveries),
],
),
),
],
),
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:hl_lieferservice/model/delivery.dart';
import 'package:hl_lieferservice/feature/delivery/detail/presentation/delivery_detail_page.dart';
class DeliveryListItem extends StatelessWidget {
final Delivery delivery;
const DeliveryListItem({super.key, required this.delivery});
Widget _leading(BuildContext context) {
if (delivery.state == DeliveryState.finished) {
return Icon(Icons.check_circle, color: Colors.green);
}
if (delivery.state == DeliveryState.canceled) {
return Icon(Icons.cancel_rounded, color: Colors.red);
}
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Icon(Icons.location_on, color: Theme.of(context).primaryColor),
Text("5min"),
],
);
}
void _goToDelivery(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DeliveryDetail(delivery: delivery),
),
);
}
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(
delivery.customer.name,
style: Theme.of(context).textTheme.titleMedium,
),
leading: _leading(context),
tileColor: Theme.of(context).colorScheme.surfaceContainerHigh,
subtitle: Text(delivery.customer.address.toString()),
trailing: Icon(Icons.arrow_forward_ios),
onTap: () => _goToDelivery(context),
);
}
}

View File

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:hl_lieferservice/model/delivery.dart';
import 'delivery_item.dart';
class DeliveryList extends StatefulWidget {
final List<Delivery> deliveries;
const DeliveryList({super.key, required this.deliveries});
@override
State<StatefulWidget> createState() => _DeliveryListState();
}
class _DeliveryListState extends State<DeliveryList> {
@override
Widget build(BuildContext context) {
if (widget.deliveries.isEmpty) {
return ListView(
children: [Center(child: const Text("Keine Auslieferungen gefunden"))],
);
}
return ListView.separated(
separatorBuilder: (context, index) => const Divider(height: 0),
itemBuilder:
(context, index) =>
DeliveryListItem(delivery: widget.deliveries[index]),
itemCount: widget.deliveries.length,
);
}
}

View File

@ -0,0 +1,119 @@
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_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/model/tour.dart';
import '../../../authentication/bloc/auth_bloc.dart';
import '../../../authentication/bloc/auth_state.dart';
class DeliveryOverview extends StatefulWidget {
const DeliveryOverview({super.key, required this.tour});
final Tour tour;
@override
State<StatefulWidget> createState() => _DeliveryOverviewState();
}
class _DeliveryOverviewState extends State<DeliveryOverview> {
String? _selectedCarPlate;
@override
void initState() {
super.initState();
// Select the first car for initialization
_selectedCarPlate = widget.tour.driver.cars.firstOrNull?.plate;
}
Future<void> _loadTour() async {
Authenticated state = context.read<AuthBloc>().state as Authenticated;
context.read<TourBloc>().add(LoadTour(teamId: state.teamId));
}
Widget _carSelection() {
return SizedBox(
width: double.infinity,
height: 50,
child: ListView(
scrollDirection: Axis.horizontal,
children:
widget.tour.driver.cars.map((car) {
Color? backgroundColor;
Color? iconColor = Theme.of(context).primaryColor;
Color? textColor;
if (_selectedCarPlate == car.plate) {
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(() {
_selectedCarPlate = car.plate;
});
},
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(),
),
);
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: _loadTour,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DeliveryInfo(tour: widget.tour),
Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
"Fahrten",
style: Theme.of(context).textTheme.headlineSmall,
),
],
),
IconButton(icon: Icon(Icons.filter_list), onPressed: () {}),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 20),
child: _carSelection(),
),
Expanded(child: DeliveryList(deliveries: widget.tour.deliveries)),
],
),
);
}
}

View File

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_overview.dart';
import '../bloc/tour_bloc.dart';
import '../bloc/tour_state.dart';
class DeliveryOverviewPage extends StatefulWidget {
const DeliveryOverviewPage({super.key});
@override
State<StatefulWidget> createState() => _DeliveryOverviewPageState();
}
class _DeliveryOverviewPageState extends State<DeliveryOverviewPage> {
@override
Widget build(BuildContext context) {
return BlocBuilder<TourBloc, TourState>(
builder: (context, state) {
if (state is TourLoaded) {
final currentState = state;
return Center(child: DeliveryOverview(tour: currentState.tour));
}
return Container();
},
);
}
}