You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
2.3 KiB
72 lines
2.3 KiB
2 years ago
|
import 'dart:async';
|
||
|
|
||
|
import 'package:flutter/foundation.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||
|
import 'package:logic_circuits_simulator/utils/logic_expressions.dart';
|
||
|
import 'package:logic_circuits_simulator/utils/logic_operators.dart';
|
||
|
|
||
|
class LogicExpressionField extends HookWidget {
|
||
|
final ValueListenable<List<String>> inputsListener;
|
||
|
final String outputName;
|
||
|
final String? initialText;
|
||
|
final void Function(String input, LogicExpression expression)? onChanged;
|
||
|
final void Function()? onInputError;
|
||
|
|
||
|
const LogicExpressionField({required this.inputsListener, required this.outputName, this.initialText, this.onChanged, this.onInputError, super.key});
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
final inputs = useValueListenable(inputsListener);
|
||
|
final controller = useTextEditingController(text: initialText);
|
||
|
final errorText = useState<String?>(null);
|
||
|
useValueListenable(controller);
|
||
|
|
||
|
final onChg = useMemoized(() => (String newValue) {
|
||
|
final trimmed = newValue.trim();
|
||
|
|
||
|
try {
|
||
|
if (trimmed.isEmpty) {
|
||
|
onChanged?.call('', LogicExpression(operator: FalseLogicOperator(), arguments: []));
|
||
|
}
|
||
|
else {
|
||
|
final newLogicExpression = LogicExpression.parse(trimmed);
|
||
|
|
||
|
// Check if unknown inputs are used
|
||
|
final newInputs = newLogicExpression.inputs;
|
||
|
final unknownInputs = newInputs.where((input) => !inputs.contains(input)).toList();
|
||
|
if (unknownInputs.isNotEmpty) {
|
||
|
throw Exception('Unknown inputs found: ${unknownInputs.join(", ")}');
|
||
|
}
|
||
|
|
||
|
onChanged?.call(trimmed, newLogicExpression);
|
||
|
}
|
||
|
errorText.value = null;
|
||
|
} catch (e) {
|
||
|
errorText.value = e.toString();
|
||
|
onInputError?.call();
|
||
|
}
|
||
|
}, [inputs, errorText]);
|
||
|
useEffect(
|
||
|
() {
|
||
|
if (controller.text.isNotEmpty) {
|
||
|
scheduleMicrotask(() {
|
||
|
onChg(controller.text);
|
||
|
});
|
||
|
}
|
||
|
return null;
|
||
|
},
|
||
|
[inputs],
|
||
|
);
|
||
|
|
||
|
return TextField(
|
||
|
controller: controller,
|
||
|
onChanged: onChg,
|
||
|
decoration: InputDecoration(
|
||
|
border: const OutlineInputBorder(),
|
||
|
labelText: 'Logic Experssion for $outputName',
|
||
|
errorText: errorText.value,
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|