import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../formula_models.dart'; import '../formula_evaluator.dart'; import '../corpus.dart'; import 'unit_dropdown.dart'; class FormulaScreen extends StatefulWidget { final Formula formula; final UnitCorpus corpus; const FormulaScreen({ super.key, required this.formula, required this.corpus, }); @override State createState() => _FormulaScreenState(); } class _FormulaScreenState extends State { final _formKey = GlobalKey(); final Map _inputControllers = {}; final Map _selectedUnits = {}; String? _result; String? _selectedOutputUnit; @override void initState() { super.initState(); // Initialize controllers and units with listeners for (final input in widget.formula.input) { _inputControllers[input.name] = TextEditingController(); _selectedUnits[input.name] = input.magnitude; _inputControllers[input.name]!.addListener(_evaluateFormula); } _selectedOutputUnit = widget.formula.output.magnitude; } @override void dispose() { // Clean up controllers and listeners for (final controller in _inputControllers.values) { controller.removeListener(_evaluateFormula); controller.dispose(); } super.dispose(); } void _evaluateFormula() { if (!_formKey.currentState!.validate()) return; try { final inputValues = {}; for (final input in widget.formula.input) { final value = double.tryParse(_inputControllers[input.name]!.text) ?? 0.0; // Convert input to base unit if needed // Always convert from dropdown unit to variable's base unit inputValues[input.name] = widget.corpus.convert( value, _selectedUnits[input.name]!, input.magnitude, ); } final evaluator = FormulaEvaluator(); final result = evaluator.evaluate(widget.formula, inputValues); // Convert output to selected unit if needed if (_selectedOutputUnit != widget.formula.output.magnitude) { _result = widget.corpus.convert( result, widget.formula.output.magnitude, _selectedOutputUnit!, ).toStringAsFixed(2); } else { _result = result.toStringAsFixed(2); } setState(() {}); } catch (e, stack) { debugPrint('Formula evaluation error: $e'); debugPrint('Stack trace: $stack'); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error: ${e.toString()}\n${stack.toString()}'), backgroundColor: Theme.of(context).colorScheme.error, ), ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.formula.name), ), body: Form( key: _formKey, child: Padding( padding: const EdgeInsets.all(16.0), child: ListView( children: [ _buildInputSection(), const SizedBox(height: 24), _buildOutputSection(), ], ), ), ), ); } Widget _buildInputSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Input Variables', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), ...widget.formula.input.map((variable) => _buildVariableRow(variable)), ], ); } Widget _buildOutputSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Result', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Row( children: [ Text(widget.formula.output.name), const Spacer(), SizedBox( width: 100, child: TextFormField( readOnly: true, enabled: false, controller: TextEditingController(text: _result), decoration: const InputDecoration( border: UnderlineInputBorder(), filled: true, ), ), ), const SizedBox(width: 8), UnitDropdown( corpus: widget.corpus, variable: widget.formula.output, selectedUnit: _selectedOutputUnit, onUnitChanged: (unit) { setState(() { _selectedOutputUnit = unit; }); }, ), ], ), ], ); } Widget _buildVariableRow(VariableSpec variable) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ Text(variable.name), const Spacer(), SizedBox( width: 100, child: TextFormField( controller: _inputControllers[variable.name], keyboardType: TextInputType.number, inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[0-9\.\-]')), ], decoration: const InputDecoration( border: UnderlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return 'Required'; } return null; }, ), ), const SizedBox(width: 8), UnitDropdown( corpus: widget.corpus, variable: variable, selectedUnit: _selectedUnits[variable.name], onUnitChanged: (unit) { setState(() { _selectedUnits[variable.name] = unit; }); _evaluateFormula(); }, ), ], ), ); } }