88 lines
2.2 KiB
Dart
88 lines
2.2 KiB
Dart
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;
|
||
}
|