algún avance con copilot en apgar
This commit is contained in:
parent
b053fc3900
commit
57becb5577
1 changed files with 120 additions and 67 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
// dart
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import '../formula_models.dart';
|
import '../formula_models.dart';
|
||||||
|
|
@ -15,9 +16,6 @@ class FormulaScreen extends StatefulWidget {
|
||||||
State<FormulaScreen> createState() => _FormulaScreenState();
|
State<FormulaScreen> createState() => _FormulaScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Create VariableWidget. Depending on VariableSpec.values, it can be a ValueDropdown or a D4rtEditingController
|
|
||||||
// The d4rtValue will be FormulaResult?
|
|
||||||
|
|
||||||
//// Start of D4rtEditingController class ////
|
//// Start of D4rtEditingController class ////
|
||||||
class D4rtEditingController extends TextEditingController {
|
class D4rtEditingController extends TextEditingController {
|
||||||
String? _lastError;
|
String? _lastError;
|
||||||
|
|
@ -34,8 +32,8 @@ class D4rtEditingController extends TextEditingController {
|
||||||
return true;
|
return true;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
_lastError = e.toString();
|
_lastError = e.toString();
|
||||||
print( "validate: $text: $e" );
|
print("validate: $text: $e");
|
||||||
print( "stack: $s" );
|
print("stack: $s");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,19 +57,25 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
final Map<String, D4rtEditingController> _inputControllers = {};
|
final Map<String, D4rtEditingController> _inputControllers = {};
|
||||||
final Map<String, String?> _selectedUnits = {};
|
final Map<String, String?> _selectedUnits = {};
|
||||||
|
final Map<String, String?> _selectedValues = {}; // for string dropdowns
|
||||||
String? _result;
|
String? _result;
|
||||||
String? _selectedOutputUnit;
|
String? _selectedOutputUnit;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// Initialize controllers and units with listeners
|
// Initialize controllers and units with listeners
|
||||||
for (final input in widget.formula.input) {
|
for (final input in widget.formula.input) {
|
||||||
_inputControllers[input.name] = D4rtEditingController();
|
|
||||||
_selectedUnits[input.name] = input.unit;
|
_selectedUnits[input.name] = input.unit;
|
||||||
|
if (input.values != null && input.values!.isNotEmpty) {
|
||||||
|
// string/categorical variable -> use dropdown
|
||||||
|
_selectedValues[input.name] = input.values!.first;
|
||||||
|
} else {
|
||||||
|
// numeric variable -> use D4rtEditingController
|
||||||
|
_inputControllers[input.name] = D4rtEditingController();
|
||||||
_inputControllers[input.name]!.addListener(_evaluateFormula);
|
_inputControllers[input.name]!.addListener(_evaluateFormula);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_selectedOutputUnit = widget.formula.output.unit;
|
_selectedOutputUnit = widget.formula.output.unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,34 +95,41 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
try {
|
try {
|
||||||
final inputValues = <String, dynamic>{};
|
final inputValues = <String, dynamic>{};
|
||||||
for (final input in widget.formula.input) {
|
for (final input in widget.formula.input) {
|
||||||
|
// string/categorical variable
|
||||||
|
if (input.values != null && input.values!.isNotEmpty) {
|
||||||
|
final selected = _selectedValues[input.name];
|
||||||
|
if (selected == null) {
|
||||||
|
_result = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inputValues[input.name] = selected;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// numeric variable - must have controller
|
||||||
final controller = _inputControllers[input.name]!;
|
final controller = _inputControllers[input.name]!;
|
||||||
if (controller.d4rtValue == null) {
|
final val = controller.d4rtValue;
|
||||||
//throw FormulaEvaluationException("Field ${input.name} is invalid");
|
if (val == null) {
|
||||||
_result = "";
|
_result = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
late final dynamic convertedValue;
|
dynamic convertedValue;
|
||||||
|
if (val is NumberResult) {
|
||||||
switch (controller.d4rtValue) {
|
|
||||||
case NumberResult nr:
|
|
||||||
// Convert input to base unit if needed
|
|
||||||
// Always convert from dropdown unit to variable's base unit
|
|
||||||
if (input.unit != null) {
|
if (input.unit != null) {
|
||||||
convertedValue = widget.corpus.convert(
|
convertedValue = widget.corpus.convert(
|
||||||
nr.value,
|
val.value,
|
||||||
_selectedUnits[input.name]!,
|
_selectedUnits[input.name]!,
|
||||||
input.unit as String,
|
input.unit as String,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
convertedValue = nr.value;
|
convertedValue = val.value;
|
||||||
}
|
}
|
||||||
|
} else if (val is StringResult) {
|
||||||
case StringResult sr:
|
convertedValue = val.value;
|
||||||
convertedValue = sr.value;
|
} else {
|
||||||
default:
|
|
||||||
throw FormulaEvaluationException(
|
throw FormulaEvaluationException(
|
||||||
"Field ${input.name} has unsupported type ${controller.d4rtValue!.runtimeType}",
|
"Field ${input.name} has unsupported type ${val.runtimeType}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,14 +142,15 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
// Convert output to selected unit if needed
|
// Convert output to selected unit if needed
|
||||||
String? unit = widget.formula.output.unit;
|
String? unit = widget.formula.output.unit;
|
||||||
if (unit != null) {
|
if (unit != null) {
|
||||||
_result = widget.corpus
|
final converted = widget.corpus.convert(result, unit, _selectedOutputUnit!);
|
||||||
.convert(result, unit, _selectedOutputUnit!)
|
if (converted is num) {
|
||||||
.toStringAsFixed(2);
|
_result = converted.toStringAsFixed(2);
|
||||||
} else {
|
} else {
|
||||||
_result = result;
|
_result = converted.toString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_result = result?.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
//print( "_evaluateFormula: result:${result} _result:${_result}");
|
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
|
|
@ -269,12 +281,51 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildVariableRow(VariableSpec variable) {
|
Widget _buildVariableRow(VariableSpec variable) {
|
||||||
|
final isCategorical = variable.values != null && variable.values!.isNotEmpty;
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(variable.name),
|
Text(variable.name),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
if (isCategorical) ...[
|
||||||
|
SizedBox(
|
||||||
|
width: 150,
|
||||||
|
child: DropdownButtonFormField<String>(
|
||||||
|
value: _selectedValues[variable.name],
|
||||||
|
items: variable.values!
|
||||||
|
.map((v) => DropdownMenuItem<String>(value: v, child: Text(v)))
|
||||||
|
.toList(),
|
||||||
|
onChanged: (v) {
|
||||||
|
setState(() {
|
||||||
|
_selectedValues[variable.name] = v;
|
||||||
|
});
|
||||||
|
_evaluateFormula();
|
||||||
|
},
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: UnderlineInputBorder(),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) return 'Required';
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
if (variable.unit != null)
|
||||||
|
UnitDropdown(
|
||||||
|
corpus: widget.corpus,
|
||||||
|
variable: variable,
|
||||||
|
selectedUnit: _selectedUnits[variable.name],
|
||||||
|
onUnitChanged: (unit) {
|
||||||
|
setState(() {
|
||||||
|
_selectedUnits[variable.name] = unit;
|
||||||
|
});
|
||||||
|
_evaluateFormula();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 100,
|
width: 100,
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
|
|
@ -296,6 +347,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
|
if (variable.unit != null)
|
||||||
UnitDropdown(
|
UnitDropdown(
|
||||||
corpus: widget.corpus,
|
corpus: widget.corpus,
|
||||||
variable: variable,
|
variable: variable,
|
||||||
|
|
@ -308,6 +360,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue