import 'package:flutter/material.dart'; import '../data/models.dart'; import '../data/repository.dart'; import '../theme/reclaim_tokens.dart'; /// Status banner above the data screens. /// /// Picks one of three voices by the active repository's mode: /// /// demo → orange T4: 'Demo-Daten · keine Rechtsberatung' /// (MockRepository on, Beirat + Juristen-Pipeline /// still missing) /// /// hub-live → petrol-signal: 'Live aus Hub' + hub label /// (HubRepository connected, list() reads real /// flow.completed events) /// /// hub-down → warm-warning: 'Hub nicht erreichbar — leere /// Liste, prüfe Hub-Tab' /// (HubRepository.connect timed out; fallback to /// empty list rather than mocked data) class ModeBanner extends StatelessWidget { const ModeBanner({super.key, required this.repository}); final EvaluationRepository repository; @override Widget build(BuildContext context) { final t = Theme.of(context).textTheme; final (color, icon, message) = switch (repository.mode) { 'hub-live' => ( ReclaimColors.signal, Icons.bolt_outlined, 'Live aus Hub · ${repository.hubLabel}. ' 'Werte stammen aus den flow.completed-Events des ' 'Ch∆In-Audit-Logs. Volljuristen-Approval-Kette ist ' 'in Phase 0 noch Selbst-Review — siehe „Recht".', ), 'hub-down' => ( ReclaimColors.harmWarm, Icons.signal_wifi_off, 'Hub nicht erreichbar — leere Liste. Konfiguration prüfen ' 'unter „Hub". Bis dahin: kein Recl∆Im-Datenpunkt ' 'sichtbar.', ), _ => ( ReclaimColors.tierT4, Icons.science_outlined, 'Demo-Daten · KEINE Rechtsberatung. Alle Zahlen sind als ' 'T4 markiert (qualitatives Signal), bis NKR-/Verbands-' 'Pipeline + Juristen-Approval laufen. Erläuterung der ' 'Stufen unter „Methodik", Disclaimer unter „Recht".', ), }; return Container( width: double.infinity, padding: const EdgeInsets.symmetric( horizontal: ReclaimSpace.lg, vertical: ReclaimSpace.sm, ), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), border: Border( bottom: BorderSide(color: color.withValues(alpha: 0.55)), ), ), child: Row( children: [ Icon(icon, size: 18, color: color), const SizedBox(width: ReclaimSpace.sm), Expanded( child: Text( message, style: t.labelSmall?.copyWith(color: color), ), ), ], ), ); } } /// Backwards-compat shim for pages that still import DemoBanner. /// Resolves to the dynamic ModeBanner if a repository is passed, /// otherwise stays demo-flavoured. class DemoBanner extends StatelessWidget { const DemoBanner({super.key, this.repository}); final EvaluationRepository? repository; @override Widget build(BuildContext context) { final repo = repository; if (repo != null) return ModeBanner(repository: repo); return const ModeBanner(repository: _DemoMockRepository()); } } /// Internal sentinel so the bare-form DemoBanner() still renders /// the orange demo voice even when no repository is plumbed in. class _DemoMockRepository implements EvaluationRepository { const _DemoMockRepository(); @override Future> list() async => const []; @override Future byEli(String eli) async => null; @override String get mode => 'demo'; @override String get hubLabel => '—'; }