build method
Describes the part of the UI represented by this widget.
Implementation
@override
Widget build(BuildContext context) {
final theme = ThemeScope.of(context);
final clamped = value.clamp(0.0, 1.0);
final (fill, track) = _resolveChars();
final filledCount = (clamped * width).round().clamp(0, width);
final fillStr = fill * filledCount;
final trackStr = track * (width - filledCount);
final fillStyle = _copyStyle(Style())..foreground(color ?? theme.primary);
final trackStyle = _copyStyle(Style())
..foreground(trackColor ?? theme.border);
final barContent =
'${fillStyle.render(fillStr)}${trackStyle.render(trackStr)}';
// Build border-wrapped bar.
String bar;
if (showBorder && (borderLeft.isNotEmpty || borderRight.isNotEmpty)) {
final bStyle = _copyStyle(Style())
..foreground(borderColor ?? theme.muted);
final left = borderLeft.isNotEmpty ? bStyle.render(borderLeft) : '';
final right = borderRight.isNotEmpty ? bStyle.render(borderRight) : '';
bar = '$left$barContent$right';
} else {
bar = barContent;
}
// Resolve label text.
final bool needsLabel = showLabel || label != null || labelFormat != null;
if (!needsLabel) {
return Text(bar);
}
final labelText = labelFormat != null
? labelFormat!(clamped)
: label ?? '${(clamped * 100).round()}%';
final resolvedLabelStyle = _copyStyle(labelStyle ?? theme.labelSmall)
..foreground(theme.muted);
if (labelPosition == ProgressLabelPosition.inside) {
// Overlay label centered inside the bar. For simplicity, render
// the bar then show the label as a separate right-aligned piece.
// In terminal mode, we just append — true overlay would need canvas.
return Row(
gap: 0,
children: [Text(bar), Text(' ${resolvedLabelStyle.render(labelText)}')],
);
}
final labelWidget = Text(labelText, style: resolvedLabelStyle);
if (labelPosition == ProgressLabelPosition.left) {
return Row(gap: 1, children: [labelWidget, Text(bar)]);
}
// Default: right
return Row(gap: 1, children: [Text(bar), labelWidget]);
}