d4t_formulas/lib/ai/FormulaWidget.dart
Álvaro González e6bd0f512f dart --fix
2025-09-05 18:53:06 +02:00

333 lines
No EOL
9.7 KiB
Dart

import 'package:flutter/material.dart';
import '../formula_models.dart';
class FormulaWidget extends StatelessWidget {
final Formula formula;
final double fontSize;
final Color? textColor;
final Color? backgroundColor;
final EdgeInsets padding;
final bool showMagnitudes;
final bool showCode;
const FormulaWidget({
super.key,
required this.formula,
this.fontSize = 16.0,
this.textColor,
this.backgroundColor,
this.padding = const EdgeInsets.all(16.0),
this.showMagnitudes = true,
this.showCode = false,
});
@override
Widget build(BuildContext context) {
return Card(
color: backgroundColor,
child: Padding(
padding: padding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
// Formula name
Text(
formula.name,
style: TextStyle(
fontSize: fontSize * 1.2,
fontWeight: FontWeight.bold,
color: textColor ?? Theme.of(context).textTheme.headlineSmall?.color,
),
),
const SizedBox(height: 12),
// Formula equation
_buildFormulaEquation(context),
if (showMagnitudes) ...[
const SizedBox(height: 16),
_buildMagnitudesSection(context),
],
if (showCode) ...[
const SizedBox(height: 16),
_buildCodeSection(context),
],
],
),
),
);
}
Widget _buildFormulaEquation(BuildContext context) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest.withOpacity(0.3),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Theme.of(context).dividerColor,
width: 1,
),
),
child: Row(
children: [
// Output variable
_buildVariableChip(formula.output, isOutput: true, context: context),
const SizedBox(width: 12),
// Equals sign
Text(
'=',
style: TextStyle(
fontSize: fontSize * 1.5,
fontWeight: FontWeight.bold,
color: textColor ?? Theme.of(context).textTheme.bodyLarge?.color,
),
),
const SizedBox(width: 12),
// Function notation
Text(
'${formula.name}(',
style: TextStyle(
fontSize: fontSize,
fontStyle: FontStyle.italic,
color: textColor ?? Theme.of(context).textTheme.bodyLarge?.color,
),
),
// Input variables
Expanded(
child: Wrap(
spacing: 8,
runSpacing: 4,
children: [
for (int i = 0; i < formula.input.length; i++) ...[
_buildVariableChip(formula.input[i], context: context),
if (i < formula.input.length - 1)
Text(
',',
style: TextStyle(
fontSize: fontSize,
color: textColor ?? Theme.of(context).textTheme.bodyLarge?.color,
),
),
],
],
),
),
Text(
')',
style: TextStyle(
fontSize: fontSize,
fontStyle: FontStyle.italic,
color: textColor ?? Theme.of(context).textTheme.bodyLarge?.color,
),
),
],
),
);
}
Widget _buildVariableChip(VariableSpec variable, {bool isOutput = false, required BuildContext context}) {
final bool hasMagnitude = variable.magnitude != VariableSpec.MAGNITUDELESS;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: isOutput
? Theme.of(context).colorScheme.primary.withOpacity(0.1)
: Theme.of(context).colorScheme.secondary.withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: isOutput
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.secondary,
width: 1,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
variable.name,
style: TextStyle(
fontSize: fontSize * 0.9,
fontWeight: FontWeight.w600,
color: isOutput
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.secondary,
),
),
if (hasMagnitude && showMagnitudes) ...[
const SizedBox(width: 4),
Text(
'[${variable.magnitude}]',
style: TextStyle(
fontSize: fontSize * 0.8,
fontStyle: FontStyle.italic,
color: (isOutput
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.secondary).withOpacity(0.7),
),
),
],
],
),
);
}
Widget _buildMagnitudesSection(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Variables:',
style: TextStyle(
fontSize: fontSize * 0.9,
fontWeight: FontWeight.w600,
color: textColor ?? Theme.of(context).textTheme.titleSmall?.color,
),
),
const SizedBox(height: 8),
Wrap(
spacing: 12,
runSpacing: 6,
children: [
...formula.input.map((variable) => _buildVariableInfo(variable, context)),
_buildVariableInfo(formula.output, context, isOutput: true),
],
),
],
);
}
Widget _buildVariableInfo(VariableSpec variable, BuildContext context, {bool isOutput = false}) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
isOutput ? Icons.arrow_forward : Icons.input,
size: fontSize * 0.8,
color: isOutput
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.secondary,
),
const SizedBox(width: 4),
Text(
'${variable.name}: ',
style: TextStyle(
fontSize: fontSize * 0.85,
fontWeight: FontWeight.w500,
color: textColor ?? Theme.of(context).textTheme.bodyMedium?.color,
),
),
Text(
variable.magnitude == VariableSpec.MAGNITUDELESS ? 'dimensionless' : variable.magnitude,
style: TextStyle(
fontSize: fontSize * 0.85,
fontStyle: FontStyle.italic,
color: (textColor ?? Theme.of(context).textTheme.bodyMedium?.color)?.withOpacity(0.8),
),
),
],
);
}
Widget _buildCodeSection(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Implementation:',
style: TextStyle(
fontSize: fontSize * 0.9,
fontWeight: FontWeight.w600,
color: textColor ?? Theme.of(context).textTheme.titleSmall?.color,
),
),
const SizedBox(height: 8),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest.withOpacity(0.5),
borderRadius: BorderRadius.circular(6),
),
child: Text(
formula.d4rtCode,
style: TextStyle(
fontSize: fontSize * 0.8,
fontFamily: 'monospace',
color: textColor ?? Theme.of(context).textTheme.bodySmall?.color,
),
),
),
],
);
}
}
// Example usage and demo
class FormulaDisplayDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Create sample formulas
final sampleFormulas = [
Formula(
name: 'calculateArea',
input: [
VariableSpec(name: 'length', magnitude: 'meters'),
VariableSpec(name: 'width', magnitude: 'meters'),
],
output: VariableSpec(name: 'area', magnitude: 'square_meters'),
d4rtCode: 'return length * width;',
),
Formula(
name: 'pythagoras',
input: [
VariableSpec(name: 'a', magnitude: 'meters'),
VariableSpec(name: 'b', magnitude: 'meters'),
],
output: VariableSpec(name: 'c', magnitude: 'meters'),
d4rtCode: 'return sqrt(a * a + b * b);',
),
Formula(
name: 'normalize',
input: [
VariableSpec(name: 'value', magnitude: VariableSpec.MAGNITUDELESS),
VariableSpec(name: 'max', magnitude: VariableSpec.MAGNITUDELESS),
],
output: VariableSpec(name: 'normalized', magnitude: VariableSpec.MAGNITUDELESS),
d4rtCode: 'return value / max;',
),
];
return Scaffold(
appBar: AppBar(
title: const Text('Formula Display Demo'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
for (final formula in sampleFormulas) ...[
FormulaWidget(
formula: formula,
showCode: true,
),
const SizedBox(height: 16),
],
],
),
),
);
}
}