// SPDX-FileCopyrightText: 2026 FocusFlow contributors // SPDX-License-Identifier: AGPL-3.0-only /// Renders Reward Icon pieces for the FocusFlow Flutter timeline. library; import 'package:flutter/material.dart'; import '../../theme/focus_flow_tokens.dart'; /// Sparkle-style reward indicator for a timeline task. class RewardIcon extends StatelessWidget { /// Creates a reward icon. const RewardIcon({ this.color = FocusFlowTokens.accentMagenta, this.size = 24, super.key, }); /// Fill color used by the icon painter. final Color color; /// Square size of the painted icon. final double size; /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return CustomPaint( size: Size.square(size), painter: _RewardIconPainter(color), ); } } /// Private implementation type for `_RewardIconPainter` in this library. /// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _RewardIconPainter extends CustomPainter { /// Creates a `_RewardIconPainter` instance with the values required by its invariants. /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _RewardIconPainter(this.color); /// Stores the `color` value for this object. /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; /// Performs the `paint` behavior for this scheduler component. /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = color ..style = PaintingStyle.fill; _drawSparkle( canvas, paint, size.center(Offset.zero), size.shortestSide * 0.44, ); _drawSparkle( canvas, paint, Offset(size.width * 0.78, size.height * 0.24), size.shortestSide * 0.18, ); _drawSparkle( canvas, paint, Offset(size.width * 0.24, size.height * 0.78), size.shortestSide * 0.14, ); } /// Runs the `_drawSparkle` helper used inside this library. /// The helper centralizes a small piece of transformation or validation so higher-level scheduler flow remains easier to read. void _drawSparkle(Canvas canvas, Paint paint, Offset center, double radius) { final path = Path() ..moveTo(center.dx, center.dy - radius) ..lineTo(center.dx + radius * 0.24, center.dy - radius * 0.24) ..lineTo(center.dx + radius, center.dy) ..lineTo(center.dx + radius * 0.24, center.dy + radius * 0.24) ..lineTo(center.dx, center.dy + radius) ..lineTo(center.dx - radius * 0.24, center.dy + radius * 0.24) ..lineTo(center.dx - radius, center.dy) ..lineTo(center.dx - radius * 0.24, center.dy - radius * 0.24) ..close(); canvas.drawPath(path, paint); } /// Performs the `shouldRepaint` behavior for this scheduler component. /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved. @override bool shouldRepaint(covariant _RewardIconPainter oldDelegate) { return oldDelegate.color != color; } }