97 lines
3.6 KiB
Dart
97 lines
3.6 KiB
Dart
// 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;
|
|
}
|
|
}
|