diff --git a/app/lib/data/fixtures.dart b/app/lib/data/fixtures.dart index 3afdea3..abf5685 100644 --- a/app/lib/data/fixtures.dart +++ b/app/lib/data/fixtures.dart @@ -90,6 +90,12 @@ class Fixtures { 'T (Tarif) T1 — DESTATIS Verdiensterhebung kaufm. Tätigkeit ~30 €/h; ' 'h (Zeitaufwand) T3 — eigene Schätzung ~30 min, NKR-Validierung ausstehend. ' 'Regel der niedrigsten Stufe: Gesamt → T3 (in der Demo konservativ als T4 markiert).', + componentSummary: const [ + 'P · T1 — DESTATIS Gewerbeanzeigen', + 'F · T1 — anlassbezogen, je Vorgang', + 'T · T1 — DESTATIS Verdiensterhebung', + 'h · T3 — eigene Schätzung ~30 min', + ], ); static final _kassenSichV = Evaluation( @@ -177,6 +183,12 @@ class Fixtures { 'Laufende Folgekosten (TSE-Ausfallmeldungen, Hardware-Erneuerung): T2 ' 'aus DIHK-Bürokratie-Index + DEHOGA-Gastronomie-Stichprobe. ' 'Hoher Frust-Score wegen Pluralität TSE-Hersteller × Finanzamt-Vollzug.', + componentSummary: const [ + 'P · T1 — Kassen-pflichtige Betriebe', + 'F · T1 — kontinuierlich + Ausfälle', + 'T · T2 — DIHK Bürokratie-Index', + 'h · T2 — DEHOGA-Stichprobe', + ], ); static final _dsgvoArt30 = Evaluation( @@ -272,6 +284,13 @@ class Fixtures { 'pro Unternehmen liegt im Streit zwischen BfDI-Position (gering, weil ' '<250-MA-Ausnahme) und DIHK-Position (hoch, weil 5-Abs.-Ausnahme ' 'praktisch nicht greift). Tier T2 für Magnitude.', + componentSummary: const [ + 'P · T1 — DESTATIS Unternehmensregister', + 'F · T1 — jährlich überprüfen', + 'T · T2 — DIHK-Position', + 'h · T2 — Streit BfDI ↔ DIHK', + 'EU-determiniert · Reform-Hebel Brüssel', + ], ); static final _berlinBauO60 = Evaluation( @@ -351,6 +370,13 @@ class Fixtures { '→ Genehmigung sind im Land getrennt geregelt). Höchster Frust-Score ' 'aus Verweistiefe + Behörden-Pluralität (Bezirksamt × SenStadt × ' 'Beteiligungsverfahren).', + componentSummary: const [ + 'P · T2 — Handwerkskammer Berlin', + 'F · T1 — pro Bauvorhaben', + 'T · T2 — Bauwirtschaft Berlin', + 'h · T3 — Verfahren mehrstufig', + 'Frust · T2 — Bezirk × Senat × Beteiligung', + ], ); static final _miLoG17 = Evaluation( @@ -428,5 +454,12 @@ class Fixtures { 'dokumentierte den initial-Erfüllungsaufwand; aktuelle Zahlen ' 'aus ZDH Bürokratiekosten-Handwerk. Bürokratieentlastungs-' 'gesetz IV adressierte den § 17 — Reform-Bewegung ist im Lauf.', + componentSummary: const [ + 'P · T1 — DESTATIS MiLoG-pflichtig', + 'F · T1 — arbeitstäglich', + 'T · T1 — DESTATIS Tariflohn', + 'h · T1 — NKR-Stellungnahme 2014', + 'Reform · BEG IV in Lauf', + ], ); } diff --git a/app/lib/data/models.dart b/app/lib/data/models.dart index ae7caf2..d75f950 100644 --- a/app/lib/data/models.dart +++ b/app/lib/data/models.dart @@ -142,6 +142,7 @@ class Evaluation { required this.sources, required this.auditEventId, this.notes, + this.componentSummary = const [], }); final Norm norm; @@ -172,4 +173,10 @@ class Evaluation { final String auditEventId; final String? notes; + + /// Compact lines for at-a-glance reading on list views. + /// One line per SKM-Komponente (P / F / T / h) plus optional + /// extras — each carries its tier-tag inline. Empty list ⇒ + /// fall back to the notes field for the list view. + final List componentSummary; } diff --git a/app/lib/pages/norms_list_page.dart b/app/lib/pages/norms_list_page.dart index 189a1fb..d6156a4 100644 --- a/app/lib/pages/norms_list_page.dart +++ b/app/lib/pages/norms_list_page.dart @@ -107,31 +107,42 @@ class _NormRow extends StatelessWidget { color: ReclaimColors.mute, ), ), + const SizedBox(height: ReclaimSpace.sm), + TierBadge(tier: evaluation.tierLowest), ], ), ), const SizedBox(width: ReclaimSpace.lg), Expanded( - child: _MetricColumn( - label: 'Schaden / Jahr', - value: _eur(evaluation.skmEurPerYear), + 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( - child: _MetricColumn( - label: 'Nutzen', - value: - '${evaluation.benefitScore.toStringAsFixed(1)} / 5', + flex: 3, + child: _ComponentSummary( + summary: evaluation.componentSummary, ), ), - Expanded( - child: _MetricColumn( - label: 'Betroffene', - value: _kmu(evaluation.affectedCount), - ), - ), - const SizedBox(width: ReclaimSpace.md), - TierBadge(tier: evaluation.tierLowest), ], ), ), @@ -152,6 +163,44 @@ class _NormRow extends StatelessWidget { } } +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});