fertig bis auf Tankstellen und Graph

This commit is contained in:
2026-01-23 15:03:18 +01:00
parent 5f4f2c4379
commit d5b8df9506
27 changed files with 2198 additions and 17 deletions

View File

@@ -11,6 +11,7 @@ class DetailPage extends GetView<DetailController> {
@override
Widget build(BuildContext context) {
var detailCtrl = controller;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey,
@@ -42,7 +43,7 @@ class DetailPage extends GetView<DetailController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header Card mit Datum und Gesamtpreis
DetailHeaderWidget(tank: controller.tank),
DetailHeaderWidget(tank: detailCtrl.tank),
const SizedBox(height: 16),
@@ -53,8 +54,8 @@ class DetailPage extends GetView<DetailController> {
DetailStatWidget(
icon: Icons.location_on,
label: 'Standort',
value: controller.tank.szLocation.isNotEmpty
? controller.tank.szLocation
value: detailCtrl.tank.szLocation.isNotEmpty
? detailCtrl.tank.szLocation
: 'Nicht angegeben',
iconColor: Colors.red,
),
@@ -62,7 +63,7 @@ class DetailPage extends GetView<DetailController> {
DetailStatWidget(
icon: Icons.calendar_today,
label: 'Datum',
value: controller.tank.szDate,
value: detailCtrl.tank.szDate,
iconColor: Colors.blueGrey,
),
],
@@ -77,7 +78,7 @@ class DetailPage extends GetView<DetailController> {
DetailStatWidget(
icon: Icons.local_gas_station,
label: 'Liter getankt',
value: '${controller.tank.szLiters} L',
value: '${detailCtrl.tank.szLiters} L',
iconColor: Colors.orange,
valueSize: 24,
valueWeight: FontWeight.bold,
@@ -89,7 +90,7 @@ class DetailPage extends GetView<DetailController> {
child: DetailStatWidget(
icon: Icons.euro,
label: 'Preis pro Liter',
value: '${controller.tank.szPricePerLiter}',
value: '${detailCtrl.tank.szPricePerLiter}',
iconColor: Colors.green,
),
),
@@ -98,7 +99,7 @@ class DetailPage extends GetView<DetailController> {
child: DetailStatWidget(
icon: Icons.receipt,
label: 'Gesamtpreis',
value: '${controller.tank.szPriceTotal}',
value: '${detailCtrl.tank.szPriceTotal}',
iconColor: Colors.green[700]!,
valueWeight: FontWeight.bold,
),
@@ -117,7 +118,7 @@ class DetailPage extends GetView<DetailController> {
DetailStatWidget(
icon: Icons.speed,
label: 'Kilometerstand',
value: '${controller.tank.szOdometer} km',
value: '${detailCtrl.tank.szOdometer} km',
iconColor: Colors.blue,
valueSize: 24,
valueWeight: FontWeight.bold,
@@ -134,6 +135,7 @@ class DetailPage extends GetView<DetailController> {
child: ElevatedButton.icon(
onPressed: () {
// Bearbeiten Funktion
detailCtrl.editEntry();
},
icon: const Icon(Icons.edit),
label: const Text('Bearbeiten'),
@@ -152,6 +154,7 @@ class DetailPage extends GetView<DetailController> {
child: ElevatedButton.icon(
onPressed: () {
// Löschen Funktion
detailCtrl.deleteEntry();
},
icon: const Icon(Icons.delete),
label: const Text('Löschen'),

294
lib/pages/edit_view.dart Normal file
View File

@@ -0,0 +1,294 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controller/edit_controller.dart';
import '../widgets/edit_form_field_widget.dart';
class EditPage extends GetView<EditController> {
static const String namedRoute = '/tank-edit-page';
const EditPage({super.key});
@override
Widget build(BuildContext context) {
var editCtrl = controller;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey,
foregroundColor: Colors.white,
title: Obx(
() => Text(
editCtrl.isNewEntry.value
? 'Neuer Tankeintrag'
: 'Tankeintrag bearbeiten',
),
),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Get.back(),
),
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.blueGrey[800]!,
Colors.blueGrey[600]!,
Colors.blueGrey[300]!,
Colors.blue[100]!,
],
),
),
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// Info Card
Obx(
() => Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(
editCtrl.isNewEntry.value
? Icons.add_circle_outline
: Icons.edit,
color: Colors.blueGrey[700],
size: 32,
),
const SizedBox(width: 16),
Expanded(
child: Text(
editCtrl.isNewEntry.value
? 'Erfassen Sie einen neuen Tankeintrag'
: 'Bearbeiten Sie Ihren Tankeintrag',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.blueGrey[900],
),
),
),
],
),
),
),
),
const SizedBox(height: 16),
// Form Card
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Datum
EditFormFieldWidget(
label: 'Datum',
icon: Icons.calendar_today,
controller: editCtrl.dateController,
isReadOnly: true,
onTap: () => editCtrl.selectDate(context),
required: true,
),
const SizedBox(height: 20),
// Kilometerstand
EditFormFieldWidget(
label: 'Kilometerstand',
icon: Icons.speed,
controller: editCtrl.odometerController,
keyboardType: TextInputType.number,
suffix: 'km',
required: true,
),
const SizedBox(height: 20),
// Liter
EditFormFieldWidget(
label: 'Liter',
icon: Icons.local_gas_station,
controller: editCtrl.litersController,
keyboardType: TextInputType.numberWithOptions(
decimal: true,
),
suffix: 'L',
required: true,
),
const SizedBox(height: 20),
// Preis pro Liter
EditFormFieldWidget(
label: 'Preis pro Liter',
icon: Icons.euro,
controller: editCtrl.pricePerLiterController,
keyboardType: TextInputType.numberWithOptions(
decimal: true,
),
suffix: '€/L',
required: true,
),
const SizedBox(height: 20),
// Standort
Obx(
() => editCtrl.isLoadingLocation.value == true
? CircularProgressIndicator()
: EditFormFieldWidget(
label: 'Standort',
icon: Icons.location_on,
controller: editCtrl.locationController,
hint: 'Optional - Tankstellenstandort',
maxLines: 2,
),
),
const SizedBox(height: 24),
// Berechneter Gesamtpreis
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.green[200]!,
width: 2,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
Icons.receipt_long,
color: Colors.green[700],
size: 28,
),
const SizedBox(width: 12),
Text(
'Gesamtpreis',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.green[900],
),
),
],
),
Obx(
() => Text(
'${editCtrl.calculatedTotal.value}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.green[700],
),
),
),
],
),
),
],
),
),
),
const SizedBox(height: 24),
// Speichern Button
Obx(
() => SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: editCtrl.isLoading.value
? null
: () => editCtrl.saveTankEntry(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blueGrey[700],
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
disabledBackgroundColor: Colors.grey[400],
),
child: editCtrl.isLoading.value
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.save),
const SizedBox(width: 8),
Text(
editCtrl.isNewEntry.value
? 'Speichern'
: 'Aktualisieren',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
const SizedBox(height: 16),
// Abbrechen Button
SizedBox(
width: double.infinity,
child: OutlinedButton(
onPressed: () => Get.back(),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.white,
side: const BorderSide(color: Colors.white, width: 2),
padding: const EdgeInsets.symmetric(vertical: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: const Text(
'Abbrechen',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
),
),
);
}
}

View File

@@ -32,6 +32,13 @@ class HomePage extends GetView<HomeController> {
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.blueGrey,
onPressed: () {
homCtrl.navigateToAddTankEntry();
},
child: const Icon(Icons.add),
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(