import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controller/bauteil_auswertung_controller.dart'; import '../helper/display_formats.dart'; import '../models/bauteil_auswertung_model.dart'; import '../models/bauteil_model.dart'; import '../theme/app_theme.dart'; import '../widgets/entry_panel.dart'; class BauteilAuswertungView extends GetView { static const routeName = '/bauteile-auswertung-view'; const BauteilAuswertungView({super.key}); @override Widget build(BuildContext context) => Scaffold( appBar: AppBar( leading: IconButton( tooltip: 'Zurück zu den Bauteilen', icon: const Icon(Icons.arrow_back), onPressed: () => Get.back(), ), title: const Text('Bauteilauswertung'), ), body: SafeArea( top: false, child: Align( alignment: Alignment.topCenter, child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 1000), child: Obx(() { final gruppen = controller.gruppen; // Headers and entries share one lazy list, even with many periods. final zeilen = [ for (final gruppe in gruppen) ...[gruppe, ...gruppe.bauteile], ]; return CustomScrollView( controller: controller.scrollController, slivers: [ SliverPadding( padding: const EdgeInsets.all(16), sliver: SliverToBoxAdapter(child: _uebersicht()), ), if (zeilen.isEmpty) const SliverToBoxAdapter( child: Padding( padding: EdgeInsets.all(24), child: Text( 'Noch keine Bauteile gespeichert.', textAlign: TextAlign.center, style: TextStyle(color: AppTheme.muted), ), ), ) else SliverPadding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 24), sliver: SliverList.builder( itemCount: zeilen.length, itemBuilder: (context, index) { final zeile = zeilen[index]; if (zeile is BauteilAuswertungsGruppe) { return _gruppenKopf(zeile); } final bauteil = zeile as BauteilModel; return Padding( padding: const EdgeInsets.only(bottom: 12), child: SavedEntryCard( key: ValueKey('auswertung-${bauteil.bauteilId}'), title: bauteil.name, subtitle: DisplayFormats.date( bauteil.erstelltAm.toLocal(), ), notes: bauteil.verwendung, details: [ BauteilAuswertungsGruppe.preisBekannt(bauteil) ? 'Gesamtpreis: ${DisplayFormats.currency(bauteil.gesamtpreis!)}' : 'Gesamtpreis nicht erfasst', '${DisplayFormats.number(bauteil.gewichtGramm)} g Bauteil', '${DisplayFormats.number(bauteil.abfallGramm)} g Abfall', DisplayFormats.duration( bauteil.druckdauerMinuten, ), ], ), ); }, ), ), ], ); }), ), ), ), ); Widget _uebersicht() => Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppTheme.inputSurface, borderRadius: BorderRadius.circular(24), border: Border.all(color: const Color(0xFFCEE6DF)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( 'Alle gedruckten Bauteile', style: TextStyle(fontSize: 23, fontWeight: FontWeight.w700), ), const SizedBox(height: 8), Text( '${controller.bauteile.length} Bauteile · neueste zuerst', style: const TextStyle(color: AppTheme.muted), ), const SizedBox(height: 16), const Text('Gesamtsumme', style: TextStyle(color: AppTheme.muted)), Text( DisplayFormats.currency(controller.gesamtsumme), style: const TextStyle( color: AppTheme.teal, fontSize: 28, fontWeight: FontWeight.w700, ), ), if (controller.ohnePreis > 0) ...[ const SizedBox(height: 8), Text( '${controller.ohnePreis} Bauteile ohne Gesamtpreis sind in der Liste enthalten, aber nicht in der Preissumme.', style: const TextStyle(color: AppTheme.muted, height: 1.5), ), ], const SizedBox(height: 24), const Text( 'Gruppieren nach', style: TextStyle(fontWeight: FontWeight.w600), ), const SizedBox(height: 8), SegmentedButton( showSelectedIcon: false, segments: const [ ButtonSegment(value: BauteilZeitraum.jahr, label: Text('Jahr')), ButtonSegment(value: BauteilZeitraum.monat, label: Text('Monat')), ButtonSegment(value: BauteilZeitraum.tag, label: Text('Tag')), ], selected: {controller.zeitraum.value}, onSelectionChanged: (auswahl) => controller.waehleZeitraum(auswahl.single), ), ], ), ); Widget _gruppenKopf(BauteilAuswertungsGruppe gruppe) => Container( margin: const EdgeInsets.only(top: 8, bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppTheme.inventorySurface, borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( controller.gruppenTitel(gruppe.beginn), style: const TextStyle( color: Colors.white, fontSize: 21, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 8), Text( '${gruppe.bauteile.length} Bauteile · Summe: ${DisplayFormats.currency(gruppe.summe)}', style: const TextStyle( color: Color(0xFF79D7C6), fontWeight: FontWeight.w600, ), ), if (gruppe.ohnePreis > 0) ...[ const SizedBox(height: 6), Text( '${gruppe.ohnePreis} ohne Gesamtpreis', style: const TextStyle(color: Color(0xFFB9CCD9)), ), ], ], ), ); }