inou/design/flutter/widgets/inou_data_row.dart

238 lines
6.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// AUTO-GENERATED widget — matches web .data-row
import 'package:flutter/material.dart';
import '../inou_theme.dart';
/// Expandable data row (for imaging, labs, etc.)
class InouDataRow extends StatefulWidget {
final String label;
final String? meta;
final String? date;
final String? value;
final bool isExpandable;
final List<Widget>? children;
final Widget? leading;
final Widget? trailing;
final VoidCallback? onTap;
final bool initiallyExpanded;
final ValueChanged<bool>? onExpandChanged;
const InouDataRow({
super.key,
required this.label,
this.meta,
this.date,
this.value,
this.isExpandable = false,
this.children,
this.leading,
this.trailing,
this.onTap,
this.initiallyExpanded = false,
this.onExpandChanged,
});
@override
State<InouDataRow> createState() => _InouDataRowState();
}
class _InouDataRowState extends State<InouDataRow> {
late bool _expanded;
@override
void initState() {
super.initState();
_expanded = widget.initiallyExpanded;
}
@override
Widget build(BuildContext context) {
return Column(
children: [
InkWell(
onTap: widget.isExpandable
? () {
setState(() => _expanded = !_expanded);
widget.onExpandChanged?.call(_expanded);
}
: widget.onTap,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: InouTheme.spaceLg,
vertical: InouTheme.spaceMd,
),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: InouTheme.border,
style: BorderStyle.solid,
),
),
),
child: Row(
children: [
if (widget.isExpandable)
SizedBox(
width: 20,
child: Text(
_expanded ? '' : '+',
style: TextStyle(
color: InouTheme.textMuted,
fontSize: 14,
fontFamily: 'monospace',
),
),
)
else if (widget.leading == null)
const SizedBox(width: 32),
if (widget.leading != null) ...[
widget.leading!,
const SizedBox(width: 12),
],
Expanded(
child: Text(
widget.label,
style: InouTheme.bodyMedium.copyWith(
fontWeight: FontWeight.w500,
),
),
),
if (widget.value != null)
Text(
widget.value!,
style: TextStyle(
fontFamily: 'SF Mono',
fontSize: 13,
color: InouTheme.text,
),
),
if (widget.meta != null) ...[
const SizedBox(width: 16),
Text(
widget.meta!,
style: InouTheme.bodySmall.copyWith(
color: InouTheme.textMuted,
),
),
],
if (widget.date != null) ...[
const SizedBox(width: 16),
Text(
widget.date!,
style: TextStyle(
fontFamily: 'SF Mono',
fontSize: 12,
color: InouTheme.textMuted,
),
),
],
if (widget.trailing != null) ...[
const SizedBox(width: 8),
widget.trailing!,
],
],
),
),
),
if (_expanded && widget.children != null)
Container(
color: InouTheme.bg,
child: Column(children: widget.children!),
),
],
);
}
}
/// Child row (indented)
class InouChildRow extends StatelessWidget {
final String label;
final String? value;
final String? meta;
final Widget? trailing;
final Color? valueColor;
const InouChildRow({
super.key,
required this.label,
this.value,
this.meta,
this.trailing,
this.valueColor,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: InouTheme.spaceLg,
vertical: InouTheme.spaceMd,
),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: InouTheme.border,
style: BorderStyle.solid,
),
),
),
child: Row(
children: [
const SizedBox(width: 32), // indent
Expanded(
child: Text(
label,
style: InouTheme.bodyMedium,
),
),
if (value != null)
Text(
value!,
style: TextStyle(
fontFamily: 'SF Mono',
fontSize: 13,
color: valueColor ?? InouTheme.text,
),
),
if (meta != null) ...[
const SizedBox(width: 16),
Text(
meta!,
style: InouTheme.bodySmall.copyWith(color: InouTheme.textMuted),
),
],
if (trailing != null) ...[
const SizedBox(width: 8),
trailing!,
],
],
),
);
}
}
/// Icon for notes/vitals
class InouNoteIcon extends StatelessWidget {
final String emoji;
final Color color;
const InouNoteIcon({
super.key,
required this.emoji,
required this.color,
});
@override
Widget build(BuildContext context) {
return Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
),
alignment: Alignment.center,
child: Text(emoji, style: const TextStyle(fontSize: 16)),
);
}
}