From 1522a4143b04ce07b119bf7ce4c37b9ed782aca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Gonz=C3=A1lez?= Date: Sun, 8 Mar 2026 10:59:20 +0100 Subject: [PATCH] Solved saving on formula edit, but problem remain in initial formula list --- lib/ai/formula_editor.dart | 1 + lib/ai/formula_screen.dart | 176 +++++++++++++++++++++---------------- lib/corpus.dart | 9 +- 3 files changed, 107 insertions(+), 79 deletions(-) diff --git a/lib/ai/formula_editor.dart b/lib/ai/formula_editor.dart index 159306d..e9ea8c8 100644 --- a/lib/ai/formula_editor.dart +++ b/lib/ai/formula_editor.dart @@ -172,6 +172,7 @@ class _FormulaEditorState extends State { ); return Formula( + uuid: widget.formula.uuid, name: _nameController.text.trim(), description: _descriptionController.text.isEmpty ? null : _descriptionController.text, input: input, diff --git a/lib/ai/formula_screen.dart b/lib/ai/formula_screen.dart index c5d1d23..3c51e3d 100644 --- a/lib/ai/formula_screen.dart +++ b/lib/ai/formula_screen.dart @@ -12,10 +12,10 @@ import 'unit_dropdown.dart'; import 'formula_editor.dart'; class FormulaScreen extends StatefulWidget { - Formula formula; + final Formula initialformula; final Corpus corpus; - FormulaScreen({super.key, required this.formula, required this.corpus}); + FormulaScreen({super.key, required formula, required this.corpus}) : initialformula = formula; @override State createState() => _FormulaScreenState(); @@ -30,12 +30,15 @@ class _FormulaScreenState extends State { String? _result; String? _selectedOutputUnit; bool _isDescriptionExpanded = false; // Track description expansion state + late Formula _formula; + + Formula get formula => _formula; + + set formula(Formula newFormula) { + _formula = newFormula; - @override - void initState() { - super.initState(); // Initialize controllers and units with listeners - for (final input in widget.formula.input) { + for (final input in formula.input) { _selectedUnits[input.name] = input.unit; if (input.values != null && input.values!.isNotEmpty) { // string/categorical variable -> use dropdown @@ -46,7 +49,13 @@ class _FormulaScreenState extends State { _inputControllers[input.name]!.addListener(_evaluateFormula); } } - _selectedOutputUnit = widget.formula.output.unit; + _selectedOutputUnit = formula.output.unit; + } + + @override + void initState() { + super.initState(); + formula = widget.initialformula; } @override @@ -62,7 +71,7 @@ class _FormulaScreenState extends State { void _evaluateFormula() { try { final inputValues = {}; - for (final input in widget.formula.input) { + for (final input in formula.input) { // string/categorical variable if (input.values != null && input.values!.isNotEmpty) { final selected = _selectedValues[input.name]; @@ -105,10 +114,10 @@ class _FormulaScreenState extends State { } final evaluator = FormulaEvaluator(); - final result = evaluator.evaluate(widget.formula, inputValues); + final result = evaluator.evaluate(formula, inputValues); // Convert output to selected unit if needed - String? unit = widget.formula.output.unit; + String? unit = formula.output.unit; if (unit != null && result is Number) { final converted = widget.corpus.convert(result, unit, _selectedOutputUnit!); if (converted is num) { @@ -126,7 +135,10 @@ class _FormulaScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error: ${e.toString()}'), - backgroundColor: Theme.of(context).colorScheme.error, + backgroundColor: Theme + .of(context) + .colorScheme + .error, ), ); } @@ -136,7 +148,7 @@ class _FormulaScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.formula.name), + title: Text(formula.name), actions: [ IconButton( icon: const Icon(Icons.edit), @@ -144,17 +156,18 @@ class _FormulaScreenState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => FormulaEditor( - formula: widget.formula, - corpus: widget.corpus, - onSave: (updatedFormula) { - // Refresh the screen after saving - setState(() { - // The corpus has been updated, refresh the displayed formula - widget.formula = updatedFormula; - }); - }, - ), + builder: (context) => + FormulaEditor( + formula: formula, + corpus: widget.corpus, + onSave: (updatedFormula) { + // Refresh the screen after saving + setState(() { + // The corpus has been updated, refresh the displayed formula + formula = updatedFormula; + }); + }, + ), ), ); }, @@ -180,8 +193,8 @@ class _FormulaScreenState extends State { } Widget _buildDescriptionSection() { - if (widget.formula.description == null || - widget.formula.description!.isEmpty) { + if (formula.description == null || + formula.description!.isEmpty) { return const SizedBox.shrink(); } @@ -190,7 +203,11 @@ class _FormulaScreenState extends State { child: ExpansionTile( title: Text( 'Description', - style: Theme.of(context).textTheme.titleMedium?.copyWith( + style: Theme + .of(context) + .textTheme + .titleMedium + ?.copyWith( fontWeight: FontWeight.bold, ), ), @@ -206,11 +223,14 @@ class _FormulaScreenState extends State { child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceVariant, + color: Theme + .of(context) + .colorScheme + .surfaceVariant, borderRadius: BorderRadius.circular(8), ), child: Markdown( - data: widget.formula.description!, + data: formula.description!, shrinkWrap: true, builders: { 'latex': LatexElementBuilder(), @@ -233,12 +253,16 @@ class _FormulaScreenState extends State { children: [ Text( 'Input Variables', - style: Theme.of( + style: Theme + .of( context, - ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ) + .textTheme + .titleMedium + ?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), - ...widget.formula.input.map((variable) => _buildVariableRow(variable)), + ...formula.input.map((variable) => _buildVariableRow(variable)), ], ); } @@ -249,9 +273,13 @@ class _FormulaScreenState extends State { children: [ Text( 'Result', - style: Theme.of( + style: Theme + .of( context, - ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ) + .textTheme + .titleMedium + ?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Row( @@ -260,7 +288,7 @@ class _FormulaScreenState extends State { SizedBox( width: 150, child: Text( - widget.formula.output.name, + formula.output.name, overflow: TextOverflow.ellipsis, ), ), @@ -280,14 +308,13 @@ class _FormulaScreenState extends State { const SizedBox(width: 8), UnitDropdown( corpus: widget.corpus, - variable: widget.formula.output, + variable: formula.output, selectedUnit: _selectedOutputUnit, onUnitChanged: (unit) { _selectedOutputUnit = unit; _evaluateFormula(); - print( "En output unit changed to $unit: $_result"); - setState(() { - }); + print("En output unit changed to $unit: $_result"); + setState(() {}); }, ), ], @@ -314,43 +341,42 @@ class _FormulaScreenState extends State { const SizedBox(width: 8), // Add some spacing // Flexible space for input field Expanded( - child: isCategorical - ? DropdownButtonFormField( - value: _selectedValues[variable.name], - items: variable.values! - .map((v) => DropdownMenuItem(value: v, child: Text(v))) - .toList(), - onChanged: (v) { - _selectedValues[variable.name] = v; - _evaluateFormula(); - setState(() { - }); - }, - decoration: const InputDecoration( - border: UnderlineInputBorder(), - ), - validator: (value) { - if (value == null || value.isEmpty) return 'Required'; - return null; - }, - ) - : TextFormField( - controller: _inputControllers[variable.name], - keyboardType: TextInputType.number, - inputFormatters: [ - //FilteringTextInputFormatter.allow(RegExp(r'[0-9\.\-]')), - ], - decoration: const InputDecoration( - border: UnderlineInputBorder(), - ), - autovalidateMode: AutovalidateMode.always, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Required'; - } - return _inputControllers[variable.name]!.lastError; - }, - ), + child: isCategorical + ? DropdownButtonFormField( + value: _selectedValues[variable.name], + items: variable.values! + .map((v) => DropdownMenuItem(value: v, child: Text(v))) + .toList(), + onChanged: (v) { + _selectedValues[variable.name] = v; + _evaluateFormula(); + setState(() {}); + }, + decoration: const InputDecoration( + border: UnderlineInputBorder(), + ), + validator: (value) { + if (value == null || value.isEmpty) return 'Required'; + return null; + }, + ) + : TextFormField( + controller: _inputControllers[variable.name], + keyboardType: TextInputType.number, + inputFormatters: [ + //FilteringTextInputFormatter.allow(RegExp(r'[0-9\.\-]')), + ], + decoration: const InputDecoration( + border: UnderlineInputBorder(), + ), + autovalidateMode: AutovalidateMode.always, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Required'; + } + return _inputControllers[variable.name]!.lastError; + }, + ), ), const SizedBox(width: 8), if (variable.unit != null) diff --git a/lib/corpus.dart b/lib/corpus.dart index aeab11b..f6939b5 100644 --- a/lib/corpus.dart +++ b/lib/corpus.dart @@ -76,18 +76,19 @@ class Corpus{ /// Updates a formula in the corpus void updateFormula(Formula formula) { - if (!_allFormulas.containsKey(formula.name)) { - throw ArgumentError("Formula not found: ${formula.name}"); + if (!_allFormulas.containsKey(formula.uuid)) { + _allFormulas.keys.forEach( (uuid)=> print("Existing formula uuid: $uuid, name: ${_allFormulas[uuid]?.name}") ); + throw ArgumentError("Formula not found: ${formula.name} ${formula.uuid}"); } // Remove old tags - final oldFormula = _allFormulas[formula.name]!; + final oldFormula = _allFormulas[formula.uuid]!; for (final tag in oldFormula.tags) { _tags[tag]?.removeWhere((f) => f.name == formula.name); } // Update the formula - _allFormulas[formula.name] = formula; + _allFormulas[formula.uuid] = formula; // Add new tags for (final tag in formula.tags) {