reclaim/app/lib/pages/heatmap_page.dart
flemming-it e08cedcd3f feat(brand): rename product to Recl∆Im (Reclaim) across app, bundle, docs
Recl∆Im — the F∆I product line for Pflicht-basierte
Wirkungsanalyse und Reform-Vorschlags-Pipelines. Replaces the
working title 'Law-Heatmap', which described the demo view
rather than the platform. Heatmap, Norms list, Hub view,
Methodik are now four panes of the same Recl∆Im app.

Renames in this commit:

  Flutter package      lawheatmap_app   -> reclaim_app
  macOS bundle id      ai.flemming.lawheatmapApp -> ai.flemming.reclaim
  macOS PRODUCT_NAME   lawheatmap_app   -> reclaim_app
  Theme tokens         LawHeatmapColors/Space/Radius/Typography/Theme
                       -> Reclaim*
  Surface card         LawHeatmapCard   -> ReclaimCard
  Top-level widget     LawHeatmapApp    -> ReclaimApp
  Theme files          lawheatmap_theme.dart/lawheatmap_tokens.dart
                       -> reclaim_theme.dart/reclaim_tokens.dart
  Widget file          lawheatmap_card.dart -> reclaim_card.dart
  Build script         build-macos.sh paths and headline string
  Docs                 MACHBARKEITSSTUDIE.md, METHODIK.md, RUN.md,
                       app/README.md, flow YAML
  UI strings           'F∆I Law-Heatmap' / 'Law-Heatmap'
                       -> 'Recl∆Im' / 'Recl∆Im (F∆I)' for vendor-
                       prefixed contexts

flutter analyze: clean. flutter test: 2/2 passing.

The local working directory stays fai_lawheatmap/ for now —
the dir is referenced by the .claude project metadata; renaming
it would break session continuity for no real gain. The Forgejo
repo was renamed via API in the same change-set (fai/lawheatmap
-> fai/reclaim), with the legacy slug serving a redirect
courtesy of Forgejo's built-in rename handling.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-18 13:42:55 +02:00

128 lines
4.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import '../data/models.dart';
import '../data/repository.dart';
import '../theme/reclaim_tokens.dart';
import '../widgets/demo_banner.dart';
import '../widgets/heatmap_grid.dart';
import '../widgets/reclaim_card.dart';
import '../widgets/tier_badge.dart';
import 'norm_detail_page.dart';
class HeatmapPage extends StatefulWidget {
const HeatmapPage({super.key, required this.repository});
final EvaluationRepository repository;
@override
State<HeatmapPage> createState() => _HeatmapPageState();
}
class _HeatmapPageState extends State<HeatmapPage> {
late Future<List<Evaluation>> _future;
@override
void initState() {
super.initState();
_future = widget.repository.list();
}
@override
Widget build(BuildContext context) {
final t = Theme.of(context).textTheme;
return Column(
children: [
const DemoBanner(),
Expanded(
child: Padding(
padding: const EdgeInsets.all(ReclaimSpace.xl),
child: FutureBuilder<List<Evaluation>>(
future: _future,
builder: (context, snap) {
if (!snap.hasData) {
return const Center(
child: CircularProgressIndicator());
}
final items = snap.data!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Heatmap', style: t.displaySmall),
const SizedBox(height: ReclaimSpace.xs),
Text(
'X: jährliche Bürokratiekosten (€, log10). '
'Y: Nutzen-Score 05. Punktgröße: Betroffenheit. '
'Klick auf einen Punkt → Detail mit Pflichten + Quellen.',
style: t.bodyLarge?.copyWith(
color: ReclaimColors.mute,
),
),
const SizedBox(height: ReclaimSpace.lg),
Expanded(
child: ReclaimCard(
accent: true,
expand: true,
child: HeatmapGrid(
evaluations: items,
onTap: (e) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => NormDetailPage(
repository: widget.repository,
evaluation: e,
),
),
);
},
),
),
),
const SizedBox(height: ReclaimSpace.lg),
Wrap(
spacing: ReclaimSpace.md,
runSpacing: ReclaimSpace.sm,
children: [
for (final e in items)
InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => NormDetailPage(
repository: widget.repository,
evaluation: e,
),
),
);
},
child: ReclaimCard(
padding: const EdgeInsets.symmetric(
horizontal: ReclaimSpace.md,
vertical: ReclaimSpace.sm,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
TierBadge(
tier: e.tierLowest, compact: true),
const SizedBox(
width: ReclaimSpace.sm),
Text(
'${e.norm.jurabk} ${e.norm.paragraph}',
style: t.labelLarge,
),
],
),
),
),
],
),
],
);
},
),
),
),
],
);
}
}