import 'package:flutter/material.dart'; /// Vertical or horizontal audio level meter. /// /// [level] is a normalised value 0.0 – 1.0. /// Colour transitions green → amber → red above 0.7. class LevelMeter extends StatelessWidget { final double level; final double width; final double height; final bool vertical; const LevelMeter({ super.key, required this.level, this.width = 24, this.height = 120, this.vertical = true, }); @override Widget build(BuildContext context) { final clamped = level.clamp(0.0, 1.0); return SizedBox( width: width, height: height, child: CustomPaint( painter: _LevelPainter(level: clamped, vertical: vertical), ), ); } } class _LevelPainter extends CustomPainter { final double level; final bool vertical; const _LevelPainter({required this.level, required this.vertical}); @override void paint(Canvas canvas, Size size) { // Background. canvas.drawRect( Rect.fromLTWH(0, 0, size.width, size.height), Paint()..color = const Color(0xFF1A1A2E), ); // Filled bar. final barColor = level < 0.6 ? const Color(0xFF00C853) // green : level < 0.8 ? const Color(0xFFFFAB00) // amber : const Color(0xFFD50000); // red final paint = Paint()..color = barColor; if (vertical) { final fillH = size.height * level; canvas.drawRect( Rect.fromLTWH(0, size.height - fillH, size.width, fillH), paint, ); } else { final fillW = size.width * level; canvas.drawRect( Rect.fromLTWH(0, 0, fillW, size.height), paint, ); } // Tick marks at 25 %, 50 %, 75 %. final tickPaint = Paint() ..color = Colors.white24 ..strokeWidth = 1; for (final frac in [0.25, 0.50, 0.75]) { if (vertical) { final y = size.height * (1.0 - frac); canvas.drawLine(Offset(0, y), Offset(size.width, y), tickPaint); } else { final x = size.width * frac; canvas.drawLine(Offset(x, 0), Offset(x, size.height), tickPaint); } } } @override bool shouldRepaint(_LevelPainter old) => old.level != level; }