feat(ui): heatmap view modes (all / jurist-reviewed / marked)

A segmented toggle over the heatmap: 'Alle' shows every evaluation,
'Geprüft (N)' filters to jurist-confirmed ones, 'Markiert' shows all
with a confirm-green check on the reviewed points. Jurists are
optional — the platform works without them and the default is 'Alle';
review only confirms a figure. Empty filtered view gets its own hint.

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-06-19 02:42:47 +02:00
parent bc3a001374
commit 4e00c83591
2 changed files with 161 additions and 3 deletions

View file

@ -14,11 +14,16 @@ class HeatmapGrid extends StatefulWidget {
super.key,
required this.evaluations,
this.onTap,
this.markReviewed = false,
});
final List<Evaluation> evaluations;
final void Function(Evaluation)? onTap;
/// When true, points whose evaluation a jurist confirmed get a
/// confirm marker (used by the heatmap's "Markiert" view mode).
final bool markReviewed;
@override
State<HeatmapGrid> createState() => _HeatmapGridState();
}
@ -45,6 +50,7 @@ class _HeatmapGridState extends State<HeatmapGrid> {
painter: _HeatmapPainter(
evaluations: widget.evaluations,
hoverIndex: _hoverIndex,
markReviewed: widget.markReviewed,
theme: Theme.of(context),
),
size: size,
@ -110,11 +116,13 @@ class _HeatmapPainter extends CustomPainter {
_HeatmapPainter({
required this.evaluations,
required this.hoverIndex,
required this.markReviewed,
required this.theme,
});
final List<Evaluation> evaluations;
final int? hoverIndex;
final bool markReviewed;
final ThemeData theme;
@override
@ -217,6 +225,33 @@ class _HeatmapPainter extends CustomPainter {
canvas.drawCircle(c, r, body);
canvas.drawCircle(c, r, ring);
// Jurist-confirmed marker (heatmap "Markiert" mode): a small
// confirm-green dot with a white check at the point's NE edge.
if (markReviewed && e.isReviewed) {
final m = Offset(c.dx + r * 0.72, c.dy - r * 0.72);
canvas.drawCircle(
m, 5.5, Paint()..color = ReclaimColors.reviewConfirmed);
canvas.drawCircle(
m,
5.5,
Paint()
..color = theme.colorScheme.surface
..style = PaintingStyle.stroke
..strokeWidth = 1.5);
final check = Path()
..moveTo(m.dx - 2.4, m.dy + 0.2)
..lineTo(m.dx - 0.6, m.dy + 2.0)
..lineTo(m.dx + 2.6, m.dy - 2.2);
canvas.drawPath(
check,
Paint()
..color = theme.colorScheme.surface
..style = PaintingStyle.stroke
..strokeWidth = 1.4
..strokeCap = StrokeCap.round
..strokeJoin = StrokeJoin.round);
}
_drawText(
canvas,
'${e.norm.jurabk} ${e.norm.paragraph}',
@ -303,5 +338,6 @@ class _HeatmapPainter extends CustomPainter {
@override
bool shouldRepaint(covariant _HeatmapPainter old) =>
old.hoverIndex != hoverIndex ||
old.markReviewed != markReviewed ||
old.evaluations.length != evaluations.length;
}