import 'dart:math' as math; import 'package:flutter/material.dart'; import '../theme.dart'; class ProgressRing extends StatelessWidget { final double percent; final double size; final double strokeWidth; final Color? color; final Color? backgroundColor; const ProgressRing({ super.key, required this.percent, this.size = 36, this.strokeWidth = 3, this.color, this.backgroundColor, }); @override Widget build(BuildContext context) { final effectiveColor = percent >= 95 ? MirrorTheme.success : (color ?? MirrorTheme.accent); return SizedBox( width: size, height: size, child: CustomPaint( painter: _ProgressRingPainter( percent: percent.clamp(0, 100), strokeWidth: strokeWidth, color: effectiveColor, backgroundColor: backgroundColor ?? MirrorTheme.surfaceLight, ), ), ); } } class _ProgressRingPainter extends CustomPainter { final double percent; final double strokeWidth; final Color color; final Color backgroundColor; _ProgressRingPainter({ required this.percent, required this.strokeWidth, required this.color, required this.backgroundColor, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = (size.width - strokeWidth) / 2; final bgPaint = Paint() ..color = backgroundColor ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth; final fgPaint = Paint() ..color = color ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth ..strokeCap = StrokeCap.round; canvas.drawCircle(center, radius, bgPaint); final sweepAngle = (percent / 100) * 2 * math.pi; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), -math.pi / 2, sweepAngle, false, fgPaint, ); } @override bool shouldRepaint(_ProgressRingPainter oldDelegate) => oldDelegate.percent != percent || oldDelegate.color != color; }