Collapsable description

This commit is contained in:
Your Name 2026-02-09 17:10:47 +01:00
parent 7728498bf9
commit 091dd9d4ec
5 changed files with 61 additions and 32 deletions

View file

@ -30,3 +30,6 @@ run-linux-debug-native: build-linux-debug-container
run-web-debug-native: build-web-debug-container run-web-debug-native: build-web-debug-container
cd build/web && python3 -m http.server $${WEB_PORT:-8081} cd build/web && python3 -m http.server $${WEB_PORT:-8081}
ai:
qwen --prompt-interactive --yolo "Read CLAUDE.md. Implement first task not already done in TODO.md"

View file

@ -1,7 +1,8 @@
[ ] Means not done [ ] Means not done
[x] Means done [x] Means done
- [ ] Unify error reporting. Create class ErrorHandler that get notified of every catched exception. This class prints the exception in stdout. - [X] Unify error reporting. Create class ErrorHandler that get notified of every catched exception. This class prints the exception in stdout.
- [ ] Make formula description collapsable in FormulaScreen. Initialy, the description is visible, but the user can hide it.
- Refactor formula and unit loading: - Refactor formula and unit loading:
- [ ] Create method `List<Object?> parseD4rtLiteral(String arrayStringLiteral). It parses a d4rt array literal (containing maps and arrays) to a List<Object?> using d4rt - [ ] Create method `List<Object?> parseD4rtLiteral(String arrayStringLiteral). It parses a d4rt array literal (containing maps and arrays) to a List<Object?> using d4rt
- [ ] Remove `fromArrayStringLiteral` from UnitSpec and Formula. - [ ] Remove `fromArrayStringLiteral` from UnitSpec and Formula.
@ -20,3 +21,4 @@
- [ ] From now on, the corpus will be loaded from database instead of assets - [ ] From now on, the corpus will be loaded from database instead of assets
- [ ] Create method List<UnitSpec> Corpus.withDependencies(Formula formula). It will return the list of units of the formula, and related units from the corpus. - [ ] Create method List<UnitSpec> Corpus.withDependencies(Formula formula). It will return the list of units of the formula, and related units from the corpus.
- [ ] Add a Share button to the formula list. It will export the array string literal of the formula with the units from Corpus.withDependencies(). - [ ] Add a Share button to the formula list. It will export the array string literal of the formula with the units from Corpus.withDependencies().
- [ ] Replace flutter-markdown with flutter-markdown-plus

View file

@ -65,6 +65,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
final Map<String, String?> _selectedValues = {}; // for string dropdowns final Map<String, String?> _selectedValues = {}; // for string dropdowns
String? _result; String? _result;
String? _selectedOutputUnit; String? _selectedOutputUnit;
bool _isDescriptionExpanded = true; // Track description expansion state
@override @override
void initState() { void initState() {
@ -194,17 +195,25 @@ class _FormulaScreenState extends State<FormulaScreen> {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return Column( return Card(
crossAxisAlignment: CrossAxisAlignment.start, margin: const EdgeInsets.only(bottom: 16),
children: [ child: ExpansionTile(
Text( title: Text(
'Description', 'Description',
style: Theme.of( style: Theme.of(context).textTheme.titleMedium?.copyWith(
context, fontWeight: FontWeight.bold,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
), ),
const SizedBox(height: 8), ),
Container( initiallyExpanded: _isDescriptionExpanded,
onExpansionChanged: (bool expanded) {
setState(() {
_isDescriptionExpanded = expanded;
});
},
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceVariant, color: Theme.of(context).colorScheme.surfaceVariant,
@ -222,8 +231,9 @@ class _FormulaScreenState extends State<FormulaScreen> {
), ),
), ),
), ),
const SizedBox(height: 24), ),
], ],
),
); );
} }

View file

@ -24,6 +24,20 @@ class ErrorHandler {
onError?.call(error, stackTrace); onError?.call(error, stackTrace);
} }
/// Convenience method to wrap code that might throw exceptions
T handleError<T>(T Function() operation, {T? defaultValue}) {
try {
return operation();
} catch (error, stackTrace) {
notify(error, stackTrace);
if (defaultValue != null) {
return defaultValue;
}
rethrow;
}
}
} }
/// Global instance of ErrorHandler for easy access /// Global instance of ErrorHandler for easy access

View file

@ -31,10 +31,10 @@ void main() {
errors.add(error); errors.add(error);
}; };
int result = errorHandler.handleError(() => 42, defaultValue: 0); int result = ErrorHandler().handleError(() => 42, defaultValue: 0);
expect(result, 42); expect(result, 42);
result = errorHandler.handleError(() { result = ErrorHandler().handleError(() {
throw Exception('Handled exception'); throw Exception('Handled exception');
}, defaultValue: 100); }, defaultValue: 100);
@ -49,7 +49,7 @@ void main() {
}; };
expect(() { expect(() {
errorHandler.handleError(() { ErrorHandler().handleError(() {
throw Exception('Rethrown exception'); throw Exception('Rethrown exception');
}); });
}, throwsA(const TypeMatcher<Exception>())); }, throwsA(const TypeMatcher<Exception>()));