build method

  1. @override
Widget build(
  1. BuildContext context
)
override

Describes the part of the UI represented by this widget.

Implementation

@override
Widget build(BuildContext context) {
  final theme = ThemeScope.of(context);
  final bg = background ?? theme.surface;
  final accent = _accentColor(theme);

  final badgeStyle = _copyStyle(theme.labelMedium)
    ..foreground(_badgeFgColor(theme))
    ..background(_badgeBgColor(theme))
    ..bold();
  final titleStyle = _copyStyle(theme.titleSmall)
    ..foreground(theme.onSurface)
    ..bold();
  final dimStyle = _copyStyle(theme.bodySmall)..foreground(theme.muted);
  final headerStyle = _copyStyle(theme.labelSmall)
    ..foreground(theme.border)
    ..bold();
  final detailStyle = _copyStyle(theme.bodySmall)..foreground(theme.border);

  final children = <Widget>[];

  // Row 1: traffic-light badge + action label
  children.add(
    Row(
      gap: 1,
      children: [
        Text(' ${data.signal.label} ', style: badgeStyle),
        Text(data.actionLabel, style: titleStyle),
      ],
    ),
  );

  // Row 2: explanation (level >= plainEnglish)
  if (data.level.index >= DisclosureLevel.plainEnglish.index &&
      data.explanation != null) {
    children.add(Text(data.explanation!, style: dimStyle));
  }

  // Evidence terms (level >= evidenceTerms)
  if (data.level.index >= DisclosureLevel.evidenceTerms.index &&
      data.evidence != null &&
      data.evidence!.isNotEmpty) {
    children.add(Text('Evidence:', style: headerStyle));
    for (final term in data.evidence!) {
      final dirChar = switch (term.direction) {
        EvidenceDirection.supporting => '+',
        EvidenceDirection.opposing => '-',
        EvidenceDirection.neutral => '~',
      };
      final dirStyle = _copyStyle(theme.bodySmall)
        ..foreground(_evidenceFgColor(theme, term.direction));
      children.add(
        Text(
          '  $dirChar ${term.label}: BF=${term.factor.toStringAsFixed(2)}',
          style: dirStyle,
        ),
      );
    }
  }

  // Full details (level >= fullDetails)
  if (data.level.index >= DisclosureLevel.fullDetails.index &&
      data.details != null) {
    final d = data.details!;
    children.add(Text('─' * 20, style: dimStyle));
    final lossStr = d.lossAvoided != null
        ? ' loss=${d.expectedLoss.toStringAsFixed(4)} avoided=${d.lossAvoided!.toStringAsFixed(4)}'
        : ' loss=${d.expectedLoss.toStringAsFixed(4)}';
    children.add(
      Text(
        'log_post=${d.logPosterior.toStringAsFixed(3)} CI=[${d.confidenceLow.toStringAsFixed(3)},${d.confidenceHigh.toStringAsFixed(3)}]$lossStr',
        style: detailStyle,
      ),
    );
  }

  return Frame(
    padding: padding ?? const EdgeInsets.all(1),
    background: bg,
    border: border ?? Border.rounded,
    borderColor: accent,
    child: Column(gap: 0, children: children),
  );
}