import 'dart:math' as math; import 'package:flutter/material.dart'; import '../theme/lawheatmap_tokens.dart'; /// The F∆I / Ch∆In brand mark: an upward triangle (the `∆`) with /// a petrol "eye" at the centre. Geometry mirrors fai_web's /// Logo.astro — the triangle IS the "A"; the eye-dot IS the dot /// of the "i". /// /// Subtle 9s breathing pulse on the eye (matches fai_web's /// `.eye-pulse`). Set [animated] to false for static contexts /// (icons, screenshots). class DeltaMark extends StatefulWidget { const DeltaMark({super.key, this.size = 64, this.animated = true}); final double size; final bool animated; @override State createState() => _DeltaMarkState(); } class _DeltaMarkState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(seconds: 9), ); if (widget.animated) { _controller.repeat(); } } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (context, _) { final t = _controller.value; // Breathe: scale 1 → 1.28 → 1 over the cycle. final pulse = 1.0 + 0.28 * (1 - (math.cos(t * 2 * math.pi).abs())); return CustomPaint( size: Size.square(widget.size), painter: _DeltaPainter(pulse: widget.animated ? pulse : 1.0), ); }, ); } } class _DeltaPainter extends CustomPainter { _DeltaPainter({required this.pulse}); final double pulse; @override void paint(Canvas canvas, Size size) { final w = size.width; final h = size.height; // Upward triangle, geometric centre. final stroke = Paint() ..color = const Color(0xFFE9E7E2) ..style = PaintingStyle.stroke ..strokeWidth = w * 0.04 ..strokeJoin = StrokeJoin.miter; final inset = w * 0.08; final tri = Path() ..moveTo(w / 2, inset) ..lineTo(w - inset, h - inset) ..lineTo(inset, h - inset) ..close(); canvas.drawPath(tri, stroke); // Eye — petrol fill, centred on the triangle's centroid. final eyeCentre = Offset(w / 2, inset + (h - 2 * inset) * 2 / 3); final eyeR = w * 0.06 * pulse; final eye = Paint()..color = LawHeatmapColors.signal; canvas.drawCircle(eyeCentre, eyeR, eye); } @override bool shouldRepaint(covariant _DeltaPainter old) => old.pulse != pulse; }