190 lines
7.0 KiB
Dart
190 lines
7.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
import '../controller/abfall_controller.dart';
|
|
import '../helper/display_formats.dart';
|
|
import '../models/abfall_model.dart';
|
|
import '../theme/app_theme.dart';
|
|
import 'entry_panel.dart';
|
|
|
|
class AbfallInventory extends StatelessWidget {
|
|
const AbfallInventory({super.key, required this.controller});
|
|
final AbfallController controller;
|
|
|
|
@override
|
|
Widget build(BuildContext context) => DecoratedSliver(
|
|
decoration: BoxDecoration(
|
|
color: AppTheme.inventorySurface,
|
|
borderRadius: BorderRadius.circular(24),
|
|
),
|
|
sliver: SliverPadding(
|
|
padding: const EdgeInsets.all(24),
|
|
sliver: Obx(() {
|
|
final entries = controller.abfaelle.toList();
|
|
final busy = controller.isSaving.value;
|
|
return SliverMainAxisGroup(
|
|
slivers: [
|
|
SliverToBoxAdapter(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'Abfallübersicht',
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 25,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
const SizedBox(height: 6),
|
|
Text(
|
|
'${entries.length} Einträge · die neuesten zuerst.',
|
|
style: const TextStyle(color: Color(0xFFB9CCD9)),
|
|
),
|
|
const SizedBox(height: 20),
|
|
Wrap(
|
|
spacing: 12,
|
|
runSpacing: 12,
|
|
children: [
|
|
_AbfallStat(
|
|
label: 'Summe Abfall',
|
|
value:
|
|
'${DisplayFormats.number(controller.summeAbfall)} g',
|
|
),
|
|
_AbfallStat(
|
|
label: 'Summe Abfallkosten',
|
|
value: DisplayFormats.currency(controller.summeKosten),
|
|
),
|
|
],
|
|
),
|
|
if (entries.any((entry) => entry.kostenUnbekannt)) ...[
|
|
const SizedBox(height: 12),
|
|
const Text(
|
|
'Bei einigen älteren Bauteilen fehlen Filamentdaten. Ihr Gewicht ist enthalten; ihre unbekannten Kosten fehlen in der Kostensumme.',
|
|
style: TextStyle(color: Color(0xFFB9CCD9), height: 1.5),
|
|
),
|
|
],
|
|
const SizedBox(height: 24),
|
|
],
|
|
),
|
|
),
|
|
if (entries.isEmpty)
|
|
const SliverToBoxAdapter(
|
|
child: Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 24),
|
|
child: Text(
|
|
'Noch kein Abfall gespeichert. Erfasse deinen ersten Eintrag.',
|
|
style: TextStyle(color: Color(0xFFB9CCD9), height: 1.5),
|
|
),
|
|
),
|
|
)
|
|
else
|
|
SliverList.separated(
|
|
itemCount: entries.length,
|
|
separatorBuilder: (context, index) =>
|
|
const SizedBox(height: 12),
|
|
itemBuilder: (context, index) {
|
|
final entry = entries[index];
|
|
return SavedEntryCard(
|
|
key: ValueKey(entry.abfallId),
|
|
title:
|
|
'${DisplayFormats.number(entry.gewichtGramm)} g Abfall',
|
|
subtitle: DisplayFormats.date(entry.datumZeit),
|
|
notes: entry.ausBauteil
|
|
? 'Aus Bauteil „${entry.bauteilName}“. Änderungen und Löschen über die Bauteilverwaltung.${entry.kostenNachtraeglich ? ' Kosten nachträglich aus den aktuellen Rollenpreisen und Startgewichten berechnet.' : ''}'
|
|
: '',
|
|
details: [
|
|
entry.kostenUnbekannt
|
|
? 'Abfallkosten: nicht ermittelbar'
|
|
: 'Abfallkosten: ${DisplayFormats.currency(entry.kosten)}',
|
|
],
|
|
trailing: entry.ausBauteil
|
|
? null
|
|
: PopupMenuButton<String>(
|
|
tooltip: 'Abfalleintrag verwalten',
|
|
enabled: !busy,
|
|
iconColor: AppTheme.ink,
|
|
onSelected: (action) {
|
|
if (action == 'edit') {
|
|
controller.editAbfall(entry);
|
|
} else if (action == 'delete') {
|
|
_confirmDelete(context, entry);
|
|
}
|
|
},
|
|
itemBuilder: (context) => const [
|
|
PopupMenuItem(
|
|
value: 'edit',
|
|
child: Text('Bearbeiten'),
|
|
),
|
|
PopupMenuItem(
|
|
value: 'delete',
|
|
child: Text('Löschen'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
|
|
Future<void> _confirmDelete(BuildContext context, AbfallModel entry) async {
|
|
final confirmed = await showDialog<bool>(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: const Text('Abfall löschen?'),
|
|
content: Text(
|
|
'${DisplayFormats.number(entry.gewichtGramm)} g Abfall vom ${DisplayFormats.date(entry.datumZeit)} löschen?',
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context, false),
|
|
child: const Text('Abbrechen'),
|
|
),
|
|
FilledButton(
|
|
onPressed: () => Navigator.pop(context, true),
|
|
child: const Text('Löschen'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
if (confirmed == true) await controller.deleteAbfall(entry.abfallId);
|
|
}
|
|
}
|
|
|
|
class _AbfallStat extends StatelessWidget {
|
|
const _AbfallStat({required this.label, required this.value});
|
|
final String label;
|
|
final String value;
|
|
|
|
@override
|
|
Widget build(BuildContext context) => Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF243E50),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: const TextStyle(color: Color(0xFFB9CCD9), fontSize: 12),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
value,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|