Merge branch 'feature/save-edited-formulas'
This commit is contained in:
commit
0d20542825
7 changed files with 122 additions and 17 deletions
2
TODO.md
2
TODO.md
|
|
@ -48,4 +48,6 @@
|
||||||
- [R] d4rtCode is a text area with dart syntax highligthing
|
- [R] d4rtCode is a text area with dart syntax highligthing
|
||||||
- [R] At the botton, a button allows to test the edited Formula, launching a FormulaScreen
|
- [R] At the botton, a button allows to test the edited Formula, launching a FormulaScreen
|
||||||
- [ ] When _FormulaScreenState._evaluateFormula() detect an error, instead of show an SnackBar, show a ExpansionTile with "⚠️ There were an error. Show details..." with the details of the exception. The ExpansionTile will be invisible if there is no error.
|
- [ ] When _FormulaScreenState._evaluateFormula() detect an error, instead of show an SnackBar, show a ExpansionTile with "⚠️ There were an error. Show details..." with the details of the exception. The ExpansionTile will be invisible if there is no error.
|
||||||
|
- [R] When FormulaEditor._save formula, ensure formula is updated in the initial FormulaList
|
||||||
|
- [ ] Refresh FormulaList each time it gets focus, so formulas are updated from corpus
|
||||||
- [ ] Investigate https://pub.dev/packages/quantity
|
- [ ] Investigate https://pub.dev/packages/quantity
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
||||||
import 'package:markdown/markdown.dart' as markdown;
|
import 'package:markdown/markdown.dart' as markdown;
|
||||||
import '../formula_models.dart';
|
import '../formula_models.dart';
|
||||||
import '../corpus.dart';
|
import '../corpus.dart';
|
||||||
|
import '../database/database_service.dart';
|
||||||
|
import '../service_locator.dart';
|
||||||
import 'formula_screen.dart';
|
import 'formula_screen.dart';
|
||||||
import 'unit_dropdown.dart';
|
import 'unit_dropdown.dart';
|
||||||
|
|
||||||
|
|
@ -13,11 +15,13 @@ import 'unit_dropdown.dart';
|
||||||
class FormulaEditor extends StatefulWidget {
|
class FormulaEditor extends StatefulWidget {
|
||||||
final Formula formula;
|
final Formula formula;
|
||||||
final Corpus corpus;
|
final Corpus corpus;
|
||||||
|
final Function(Formula)? onSave; // Callback when formula is saved
|
||||||
|
|
||||||
const FormulaEditor({
|
const FormulaEditor({
|
||||||
super.key,
|
super.key,
|
||||||
required this.formula,
|
required this.formula,
|
||||||
required this.corpus,
|
required this.corpus,
|
||||||
|
this.onSave,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -181,7 +185,7 @@ class _FormulaEditorState extends State<FormulaEditor> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _saveFormula() {
|
Future<void> _saveFormula() async {
|
||||||
if (!_validateFormula()) {
|
if (!_validateFormula()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -189,14 +193,34 @@ class _FormulaEditorState extends State<FormulaEditor> {
|
||||||
final formula = _buildFormula();
|
final formula = _buildFormula();
|
||||||
if (formula == null) return;
|
if (formula == null) return;
|
||||||
|
|
||||||
// For now, just show a success message
|
try {
|
||||||
// In a real implementation, this would save to database
|
final database = getDatabase();
|
||||||
|
|
||||||
|
// Update corpus in memory
|
||||||
|
widget.corpus.updateFormula(formula);
|
||||||
|
|
||||||
|
// Update database
|
||||||
|
final updated = await database.updateFormula(formula);
|
||||||
|
|
||||||
|
if (!updated) {
|
||||||
|
// If formula wasn't found (e.g., name changed), add it as new
|
||||||
|
await database.addFormula(formula);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the onSave callback if provided
|
||||||
|
widget.onSave?.call(formula);
|
||||||
|
|
||||||
|
// Show success message
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Formula "${formula.name}" saved successfully!'),
|
content: Text('Formula "${formula.name}" saved successfully!'),
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} catch (e, stack) {
|
||||||
|
print('Error saving formula: $e\n$stack');
|
||||||
|
_showErrorDialog('Error saving formula: $e');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showErrorDialog(String message) {
|
void _showErrorDialog(String message) {
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,10 @@ import 'package:share_plus/share_plus.dart';
|
||||||
|
|
||||||
class FormulaList extends StatefulWidget {
|
class FormulaList extends StatefulWidget {
|
||||||
final Corpus corpus;
|
final Corpus corpus;
|
||||||
final List<Formula> formulas;
|
|
||||||
|
|
||||||
const FormulaList({
|
const FormulaList({
|
||||||
super.key,
|
super.key,
|
||||||
required this.corpus,
|
required this.corpus,
|
||||||
required this.formulas,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -44,9 +42,9 @@ class _FormulaListState extends State<FormulaList> {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Formula> get _filteredFormulas {
|
List<Formula> get _filteredFormulas {
|
||||||
if (_searchQuery.isEmpty) return widget.formulas;
|
if (_searchQuery.isEmpty) return widget.corpus.getFormulas();
|
||||||
|
|
||||||
return widget.formulas.where((formula) {
|
return widget.corpus.getFormulas().where((formula) {
|
||||||
final nameMatch = formula.name.toLowerCase().contains(_searchQuery);
|
final nameMatch = formula.name.toLowerCase().contains(_searchQuery);
|
||||||
final tagMatch = formula.tags.any((tag) => tag.toLowerCase().contains(_searchQuery));
|
final tagMatch = formula.tags.any((tag) => tag.toLowerCase().contains(_searchQuery));
|
||||||
return nameMatch || tagMatch;
|
return nameMatch || tagMatch;
|
||||||
|
|
@ -119,14 +117,14 @@ class _FormulaListState extends State<FormulaList> {
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text('Error'),
|
title: const Text('Error'),
|
||||||
content: Text(message),
|
content: Text(message),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text('OK'),
|
child: const Text('OK'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,12 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
builder: (context) => FormulaEditor(
|
builder: (context) => FormulaEditor(
|
||||||
formula: widget.formula,
|
formula: widget.formula,
|
||||||
corpus: widget.corpus,
|
corpus: widget.corpus,
|
||||||
|
onSave: (updatedFormula) {
|
||||||
|
// Refresh the screen after saving
|
||||||
|
setState(() {
|
||||||
|
// The corpus has been updated, refresh the displayed formula
|
||||||
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,27 @@ class Corpus{
|
||||||
return _allFormulas.get(name);
|
return _allFormulas.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates a formula in the corpus
|
||||||
|
void updateFormula(Formula formula) {
|
||||||
|
if (!_allFormulas.containsKey(formula.name)) {
|
||||||
|
throw ArgumentError("Formula not found: ${formula.name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old tags
|
||||||
|
final oldFormula = _allFormulas[formula.name]!;
|
||||||
|
for (final tag in oldFormula.tags) {
|
||||||
|
_tags[tag]?.removeWhere((f) => f.name == formula.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the formula
|
||||||
|
_allFormulas[formula.name] = formula;
|
||||||
|
|
||||||
|
// Add new tags
|
||||||
|
for (final tag in formula.tags) {
|
||||||
|
_tags[tag]?.add(formula);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final Multimap<String, String> _baseToUnits = Multimap.create();
|
final Multimap<String, String> _baseToUnits = Multimap.create();
|
||||||
final Map<String, UnitSpec> _allUnits = {};
|
final Map<String, UnitSpec> _allUnits = {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,59 @@ extension CorpusDatabaseExtension on FormulasDatabase {
|
||||||
await insertFormulaElement(element.toStringLiteral());
|
await insertFormulaElement(element.toStringLiteral());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to update a formula in the database by name
|
||||||
|
Future<bool> updateFormula(models.Formula formula) async {
|
||||||
|
final elements = await getAllFormulaElements();
|
||||||
|
|
||||||
|
for (final element in elements) {
|
||||||
|
try {
|
||||||
|
final parsed = models.parseCorpusElements('[${element.elementText}]');
|
||||||
|
if (parsed.isNotEmpty && parsed.first is models.Formula) {
|
||||||
|
final existingFormula = parsed.first as models.Formula;
|
||||||
|
if (existingFormula.name == formula.name) {
|
||||||
|
// Update this element
|
||||||
|
await updateFormulaElement(
|
||||||
|
element.id,
|
||||||
|
formula.toStringLiteral()
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error parsing database element during update: $e');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Formula not found
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to add a new formula to the database
|
||||||
|
Future<void> addFormula(models.Formula formula) async {
|
||||||
|
await insertFormulaElement(formula.toStringLiteral());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to delete a formula from the database by name
|
||||||
|
Future<bool> deleteFormula(String formulaName) async {
|
||||||
|
final elements = await getAllFormulaElements();
|
||||||
|
|
||||||
|
for (final element in elements) {
|
||||||
|
try {
|
||||||
|
final parsed = models.parseCorpusElements('[${element.elementText}]');
|
||||||
|
if (parsed.isNotEmpty && parsed.first is models.Formula) {
|
||||||
|
final existingFormula = parsed.first as models.Formula;
|
||||||
|
if (existingFormula.name == formulaName) {
|
||||||
|
await deleteFormulaElement(element.id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error parsing database element during delete: $e');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Formula not found
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,7 @@ class _CorpusLoaderState extends State<CorpusLoader> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Formulas')),
|
appBar: AppBar(title: const Text('Formulas')),
|
||||||
body: FormulaList(
|
body: FormulaList(
|
||||||
corpus: corpus,
|
corpus: snapshot.data!,
|
||||||
formulas: snapshot.data!.getFormulas(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue