import 'package:flutter/material.dart'; import '../data/models.dart'; import '../data/repository.dart'; import '../theme/reclaim_tokens.dart'; import '../widgets/mode_banner.dart'; import '../widgets/reclaim_card.dart'; import '../widgets/tier_badge.dart'; import 'norm_detail_page.dart'; class NormsListPage extends StatelessWidget { const NormsListPage({super.key, required this.repository}); final EvaluationRepository repository; @override Widget build(BuildContext context) { final t = Theme.of(context).textTheme; return Column( children: [ ModeBanner(repository: repository), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(ReclaimSpace.xl), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Normen-Pilotkorpus', style: t.displaySmall), const SizedBox(height: ReclaimSpace.xs), Text( '5 Normen für den vertikalen Durchstich. ' 'Korpus erweiterbar in Phase 1.', style: t.bodyLarge?.copyWith( color: ReclaimColors.mute, ), ), const SizedBox(height: ReclaimSpace.lg), FutureBuilder>( future: repository.list(), builder: (context, snap) { if (!snap.hasData) { return const Center( child: CircularProgressIndicator()); } return Column( children: [ for (final e in snap.data!) Padding( padding: const EdgeInsets.only( bottom: ReclaimSpace.md), child: _NormRow( evaluation: e, repository: repository, ), ), ], ); }, ), ], ), ), ), ], ); } } class _NormRow extends StatelessWidget { const _NormRow({required this.evaluation, required this.repository}); final Evaluation evaluation; final EvaluationRepository repository; @override Widget build(BuildContext context) { final t = Theme.of(context).textTheme; return InkWell( onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (_) => NormDetailPage( repository: repository, evaluation: evaluation, ), ), ); }, child: ReclaimCard( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 4, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${evaluation.norm.jurabk} ${evaluation.norm.paragraph} — ${evaluation.norm.title}', style: t.titleMedium, ), const SizedBox(height: 4), Text( evaluation.norm.eli, style: t.labelSmall?.copyWith( fontFamily: ReclaimTypography.mono, color: ReclaimColors.mute, ), ), const SizedBox(height: ReclaimSpace.sm), TierBadge(tier: evaluation.tierLowest), ], ), ), const SizedBox(width: ReclaimSpace.lg), Expanded( flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _MetricColumn( label: 'Schaden / Jahr', value: _eur(evaluation.skmEurPerYear), ), const SizedBox(height: ReclaimSpace.sm), _MetricColumn( label: 'Nutzen', value: '${evaluation.benefitScore.toStringAsFixed(1)} / 5', ), const SizedBox(height: ReclaimSpace.sm), _MetricColumn( label: 'Betroffene', value: _kmu(evaluation.affectedCount), ), ], ), ), const SizedBox(width: ReclaimSpace.lg), Expanded( flex: 3, child: _ComponentSummary( summary: evaluation.componentSummary, ), ), ], ), ), ); } String _eur(double v) { if (v >= 1e9) return '${(v / 1e9).toStringAsFixed(2)} Mrd €'; if (v >= 1e6) return '${(v / 1e6).toStringAsFixed(1)} Mio €'; if (v >= 1e3) return '${(v / 1e3).toStringAsFixed(0)} k €'; return '${v.toStringAsFixed(0)} €'; } String _kmu(int n) { if (n >= 1_000_000) return '${(n / 1e6).toStringAsFixed(1)} Mio'; if (n >= 1_000) return '${(n / 1e3).toStringAsFixed(0)} k'; return n.toString(); } } class _ComponentSummary extends StatelessWidget { const _ComponentSummary({required this.summary}); final List summary; @override Widget build(BuildContext context) { final t = Theme.of(context).textTheme; if (summary.isEmpty) { return Text( '—', style: t.labelSmall?.copyWith(color: ReclaimColors.mute), ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Komponenten', style: t.labelSmall?.copyWith(color: ReclaimColors.mute), ), const SizedBox(height: 4), for (final line in summary) Padding( padding: const EdgeInsets.only(bottom: 2), child: Text( line, style: t.bodyLarge?.copyWith( height: 1.35, fontSize: 12.5, ), ), ), ], ); } } class _MetricColumn extends StatelessWidget { const _MetricColumn({required this.label, required this.value}); final String label; final String value; @override Widget build(BuildContext context) { final t = Theme.of(context).textTheme; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: t.labelSmall?.copyWith(color: ReclaimColors.mute), ), const SizedBox(height: 2), Text(value, style: t.titleMedium), ], ); } }