2026-06-07 11:42:44 +02:00
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
|
|
import 'package:file_picker/file_picker.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
import 'package:flutter/services.dart';
|
2026-06-07 11:42:44 +02:00
|
|
|
import 'package:path/path.dart' as p;
|
|
|
|
|
import '../../l10n/app_localizations.dart';
|
|
|
|
|
import '../../models/chart.dart';
|
|
|
|
|
import '../../models/slide.dart';
|
|
|
|
|
import '_editor_field.dart';
|
|
|
|
|
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
/// Editor for a chart slide: type, title, and an editable data grid. Data can
|
|
|
|
|
/// be entered directly in the interface, imported from a CSV (inline), or
|
|
|
|
|
/// linked to a CSV file kept in the deck's data/ directory (the living source).
|
2026-06-07 11:42:44 +02:00
|
|
|
class ChartEditor extends StatefulWidget {
|
|
|
|
|
final Slide slide;
|
|
|
|
|
final ValueChanged<Slide> onUpdate;
|
|
|
|
|
final String? projectPath;
|
|
|
|
|
|
|
|
|
|
const ChartEditor({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.slide,
|
|
|
|
|
required this.onUpdate,
|
|
|
|
|
this.projectPath,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<ChartEditor> createState() => _ChartEditorState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _ChartEditorState extends State<ChartEditor> {
|
|
|
|
|
late final TextEditingController _title;
|
|
|
|
|
late ChartType _type;
|
|
|
|
|
String? _source;
|
|
|
|
|
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
// Editable grid model (strings while editing).
|
|
|
|
|
List<String> _xLabels = [];
|
|
|
|
|
List<String> _seriesNames = [];
|
|
|
|
|
List<List<String>> _values = []; // [row][col]
|
|
|
|
|
|
|
|
|
|
// Bumped on structural changes so cell fields rebuild with fresh values.
|
|
|
|
|
int _rev = 0;
|
|
|
|
|
|
|
|
|
|
static const _labelW = 130.0;
|
|
|
|
|
static const _cellW = 96.0;
|
|
|
|
|
|
2026-06-07 11:42:44 +02:00
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
final spec = ChartSpec.parse(widget.slide.customMarkdown);
|
|
|
|
|
_type = spec.type;
|
|
|
|
|
_source = spec.source;
|
|
|
|
|
_title = TextEditingController(text: spec.title);
|
|
|
|
|
_title.addListener(_emit);
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
_loadFromSpec(spec);
|
2026-06-07 11:42:44 +02:00
|
|
|
}
|
|
|
|
|
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
void _loadFromSpec(ChartSpec spec) {
|
|
|
|
|
if (spec.hasInlineData) {
|
|
|
|
|
_seriesNames = [for (final s in spec.series) s.name];
|
|
|
|
|
_xLabels = List<String>.from(spec.x);
|
|
|
|
|
_values = [
|
|
|
|
|
for (var r = 0; r < spec.x.length; r++)
|
|
|
|
|
[
|
|
|
|
|
for (final s in spec.series)
|
|
|
|
|
r < s.data.length ? _fmt(s.data[r]) : '',
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
} else {
|
|
|
|
|
// Sensible empty starting grid.
|
|
|
|
|
_seriesNames = ['Reeks 1'];
|
|
|
|
|
_xLabels = ['', '', ''];
|
|
|
|
|
_values = List.generate(3, (_) => ['']);
|
2026-06-07 11:42:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static String _fmt(double v) =>
|
|
|
|
|
v == v.roundToDouble() ? v.toInt().toString() : v.toString();
|
|
|
|
|
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
_title.dispose();
|
|
|
|
|
super.dispose();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-07 11:42:44 +02:00
|
|
|
void _emit() {
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
final series = <ChartSeries>[
|
|
|
|
|
for (var c = 0; c < _seriesNames.length; c++)
|
|
|
|
|
ChartSeries(
|
|
|
|
|
name: _seriesNames[c],
|
|
|
|
|
data: [
|
|
|
|
|
for (var r = 0; r < _values.length; r++)
|
|
|
|
|
double.tryParse(
|
|
|
|
|
(c < _values[r].length ? _values[r][c] : '')
|
|
|
|
|
.trim()
|
|
|
|
|
.replaceAll(',', '.'),
|
|
|
|
|
) ??
|
|
|
|
|
0,
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
];
|
2026-06-07 11:42:44 +02:00
|
|
|
final spec = ChartSpec(
|
|
|
|
|
type: _type,
|
|
|
|
|
title: _title.text,
|
|
|
|
|
source: _source,
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
x: List<String>.from(_xLabels),
|
|
|
|
|
series: series,
|
2026-06-07 11:42:44 +02:00
|
|
|
);
|
|
|
|
|
widget.onUpdate(widget.slide.copyWith(customMarkdown: spec.toBlock()));
|
|
|
|
|
}
|
|
|
|
|
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
void _bump() => setState(() => _rev++);
|
|
|
|
|
|
|
|
|
|
void _addColumn() {
|
|
|
|
|
_seriesNames.add('Reeks ${_seriesNames.length + 1}');
|
|
|
|
|
for (final row in _values) {
|
|
|
|
|
row.add('');
|
|
|
|
|
}
|
|
|
|
|
_bump();
|
|
|
|
|
_emit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _removeColumn(int c) {
|
|
|
|
|
if (_seriesNames.length <= 1) return;
|
|
|
|
|
_seriesNames.removeAt(c);
|
|
|
|
|
for (final row in _values) {
|
|
|
|
|
if (c < row.length) row.removeAt(c);
|
|
|
|
|
}
|
|
|
|
|
_bump();
|
|
|
|
|
_emit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _addRow() {
|
|
|
|
|
_xLabels.add('');
|
|
|
|
|
_values.add(List<String>.filled(_seriesNames.length, '', growable: true));
|
|
|
|
|
_bump();
|
|
|
|
|
_emit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _removeRow(int r) {
|
|
|
|
|
if (_xLabels.length <= 1) return;
|
|
|
|
|
_xLabels.removeAt(r);
|
|
|
|
|
_values.removeAt(r);
|
|
|
|
|
_bump();
|
|
|
|
|
_emit();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-07 11:42:44 +02:00
|
|
|
Future<void> _importCsv() async {
|
|
|
|
|
final result = await FilePicker.pickFiles(
|
|
|
|
|
type: FileType.custom,
|
|
|
|
|
allowedExtensions: ['csv'],
|
|
|
|
|
withData: true,
|
|
|
|
|
);
|
|
|
|
|
if (result == null || result.files.isEmpty) return;
|
|
|
|
|
final file = result.files.first;
|
|
|
|
|
final text = file.bytes != null
|
|
|
|
|
? utf8.decode(file.bytes!)
|
|
|
|
|
: (file.path != null ? await File(file.path!).readAsString() : null);
|
|
|
|
|
if (text == null) return;
|
|
|
|
|
|
|
|
|
|
var asFile = false;
|
|
|
|
|
if (widget.projectPath != null && mounted) {
|
|
|
|
|
asFile =
|
|
|
|
|
await showDialog<bool>(
|
|
|
|
|
context: context,
|
|
|
|
|
builder: (ctx) => AlertDialog(
|
|
|
|
|
title: Text(ctx.l10n.d('CSV importeren')),
|
|
|
|
|
content: Text(
|
|
|
|
|
ctx.l10n.d(
|
|
|
|
|
'Data in de slide opslaan, of als los CSV-bestand naast de presentatie bewaren?',
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
actions: [
|
|
|
|
|
TextButton(
|
|
|
|
|
onPressed: () => Navigator.pop(ctx, false),
|
|
|
|
|
child: Text(ctx.l10n.d('In de slide')),
|
|
|
|
|
),
|
|
|
|
|
TextButton(
|
|
|
|
|
onPressed: () => Navigator.pop(ctx, true),
|
|
|
|
|
child: Text(ctx.l10n.d('Als CSV-bestand')),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
) ??
|
|
|
|
|
false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String? source;
|
|
|
|
|
if (asFile && widget.projectPath != null) {
|
|
|
|
|
final name = p.basename(file.name);
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
final dir = Directory(p.join(widget.projectPath!, chartDataDirName));
|
2026-06-07 11:42:44 +02:00
|
|
|
await dir.create(recursive: true);
|
|
|
|
|
await File(p.join(dir.path, name)).writeAsString(text, flush: true);
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
source = '$chartDataDirName/$name';
|
2026-06-07 11:42:44 +02:00
|
|
|
}
|
|
|
|
|
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
final parsed = parseCsv(text);
|
2026-06-07 11:42:44 +02:00
|
|
|
setState(() {
|
|
|
|
|
_source = source;
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
_xLabels = parsed.$1.isEmpty ? [''] : parsed.$1;
|
|
|
|
|
_seriesNames = parsed.$2.isEmpty
|
|
|
|
|
? ['Reeks 1']
|
|
|
|
|
: [for (final s in parsed.$2) s.name];
|
|
|
|
|
_values = [
|
|
|
|
|
for (var r = 0; r < _xLabels.length; r++)
|
|
|
|
|
[for (final s in parsed.$2) r < s.data.length ? _fmt(s.data[r]) : ''],
|
|
|
|
|
];
|
|
|
|
|
_rev++;
|
2026-06-07 11:42:44 +02:00
|
|
|
});
|
|
|
|
|
_emit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _unlink() {
|
|
|
|
|
setState(() => _source = null);
|
|
|
|
|
_emit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
final l10n = context.l10n;
|
|
|
|
|
final linked = _source != null;
|
|
|
|
|
return Padding(
|
|
|
|
|
padding: const EdgeInsets.all(16),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
EditorField(label: 'Titel (optioneel)', controller: _title),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
l10n.d('Type grafiek'),
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
|
color: Color(0xFF64748B),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(width: 12),
|
|
|
|
|
DropdownButton<ChartType>(
|
|
|
|
|
value: _type,
|
|
|
|
|
isDense: true,
|
|
|
|
|
borderRadius: BorderRadius.circular(6),
|
|
|
|
|
style: const TextStyle(fontSize: 12, color: Color(0xFF0F172A)),
|
|
|
|
|
items: [
|
|
|
|
|
DropdownMenuItem(
|
|
|
|
|
value: ChartType.bar,
|
|
|
|
|
child: Text(l10n.d('Staaf')),
|
|
|
|
|
),
|
|
|
|
|
DropdownMenuItem(
|
|
|
|
|
value: ChartType.line,
|
|
|
|
|
child: Text(l10n.d('Lijn')),
|
|
|
|
|
),
|
|
|
|
|
DropdownMenuItem(
|
|
|
|
|
value: ChartType.pie,
|
|
|
|
|
child: Text(l10n.d('Cirkel')),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
onChanged: (v) {
|
|
|
|
|
if (v == null) return;
|
|
|
|
|
setState(() => _type = v);
|
|
|
|
|
_emit();
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
const Spacer(),
|
|
|
|
|
TextButton.icon(
|
|
|
|
|
onPressed: _importCsv,
|
|
|
|
|
icon: const Icon(Icons.upload_file, size: 16),
|
|
|
|
|
label: Text(l10n.d('CSV importeren')),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
if (linked)
|
|
|
|
|
Padding(
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
padding: const EdgeInsets.only(top: 8),
|
2026-06-07 11:42:44 +02:00
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
const Icon(Icons.link, size: 14, color: Color(0xFF0369A1)),
|
|
|
|
|
const SizedBox(width: 6),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Text(
|
|
|
|
|
'${l10n.d('Gekoppeld aan')} $_source',
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontSize: 11,
|
|
|
|
|
color: Color(0xFF0369A1),
|
|
|
|
|
),
|
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
TextButton(
|
|
|
|
|
onPressed: _unlink,
|
|
|
|
|
child: Text(l10n.d('Ontkoppelen')),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
const SizedBox(height: 12),
|
2026-06-07 11:42:44 +02:00
|
|
|
Expanded(
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
child: SingleChildScrollView(
|
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
|
scrollDirection: Axis.horizontal,
|
|
|
|
|
child: _grid(enabled: !linked),
|
2026-06-07 11:42:44 +02:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
if (!linked) ...[
|
|
|
|
|
const SizedBox(height: 8),
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
OutlinedButton.icon(
|
|
|
|
|
onPressed: _addRow,
|
|
|
|
|
icon: const Icon(Icons.add, size: 16),
|
|
|
|
|
label: Text(l10n.d('Rij')),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(width: 8),
|
|
|
|
|
OutlinedButton.icon(
|
|
|
|
|
onPressed: _addColumn,
|
|
|
|
|
icon: const Icon(Icons.add, size: 16),
|
|
|
|
|
label: Text(l10n.d('Reeks')),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
2026-06-07 11:42:44 +02:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
Add project docs, EUPL licence, and open-source licence check
Documentation & licensing:
- Add the EUPL-1.2 licence (LICENSE.md) and set the project licence; refresh
the README (name origin wink, updated feature list, documentation index).
- Add CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, AUTHORS, and
THIRD_PARTY_NOTICES, plus docs/ (ARCHITECTURE, BUILD, USER_GUIDE, SHORTCUTS,
LICENSE_COMPLIANCE) and .github/ (CI workflow, issue/PR templates).
- Bring docs/FILE_FORMAT.md in line with current behaviour (code & chart
slides, per-slide TLP comment, annotation .ink.json sidecar, chart data/ CSVs).
Open-source compliance:
- Add tool/check_licenses.dart and a `make licenses` target (wired into
check-full and CI) that verifies every resolved dependency uses a recognised
open-source licence. A scan of all 151 packages and bundled assets found only
OSI-approved licences.
Charts (Fase 1.1):
- Replace the chart CSV textarea with an in-app editable data grid (editable
series/labels/values, add/remove row & column, read-only when linked).
- Centralize the linked-CSV directory name (`data/`) in a shared constant.
Also normalize formatting repo-wide with `dart format` and fix one
curly-braces lint, so `make check` and CI are green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:19:56 +02:00
|
|
|
|
|
|
|
|
Widget _grid({required bool enabled}) {
|
|
|
|
|
final cols = _seriesNames.length;
|
|
|
|
|
return Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
// Header row: empty label cell + series name fields.
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: _labelW,
|
|
|
|
|
child: _headerHint(context.l10n.d('Label')),
|
|
|
|
|
),
|
|
|
|
|
for (var c = 0; c < cols; c++)
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: _cellW,
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
Expanded(
|
|
|
|
|
child: _cell(
|
|
|
|
|
key: ValueKey('s-$_rev-$c'),
|
|
|
|
|
value: _seriesNames[c],
|
|
|
|
|
enabled: enabled,
|
|
|
|
|
onChanged: (v) => _seriesNames[c] = v,
|
|
|
|
|
bold: true,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
if (enabled && cols > 1)
|
|
|
|
|
_iconBtn(Icons.close, () => _removeColumn(c)),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 4),
|
|
|
|
|
// Data rows.
|
|
|
|
|
for (var r = 0; r < _xLabels.length; r++)
|
|
|
|
|
Padding(
|
|
|
|
|
padding: const EdgeInsets.only(bottom: 4),
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: _labelW,
|
|
|
|
|
child: _cell(
|
|
|
|
|
key: ValueKey('x-$_rev-$r'),
|
|
|
|
|
value: _xLabels[r],
|
|
|
|
|
enabled: enabled,
|
|
|
|
|
onChanged: (v) => _xLabels[r] = v,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
for (var c = 0; c < cols; c++)
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: _cellW,
|
|
|
|
|
child: _cell(
|
|
|
|
|
key: ValueKey('v-$_rev-$r-$c'),
|
|
|
|
|
value: c < _values[r].length ? _values[r][c] : '',
|
|
|
|
|
enabled: enabled,
|
|
|
|
|
number: true,
|
|
|
|
|
onChanged: (v) {
|
|
|
|
|
while (_values[r].length <= c) {
|
|
|
|
|
_values[r].add('');
|
|
|
|
|
}
|
|
|
|
|
_values[r][c] = v;
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
if (enabled && _xLabels.length > 1)
|
|
|
|
|
_iconBtn(Icons.close, () => _removeRow(r)),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _headerHint(String text) => Padding(
|
|
|
|
|
padding: const EdgeInsets.only(left: 4, bottom: 4),
|
|
|
|
|
child: Text(
|
|
|
|
|
text,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontSize: 11,
|
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
|
color: Color(0xFF94A3B8),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Widget _cell({
|
|
|
|
|
required Key key,
|
|
|
|
|
required String value,
|
|
|
|
|
required bool enabled,
|
|
|
|
|
required ValueChanged<String> onChanged,
|
|
|
|
|
bool number = false,
|
|
|
|
|
bool bold = false,
|
|
|
|
|
}) {
|
|
|
|
|
return Padding(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 2),
|
|
|
|
|
child: TextFormField(
|
|
|
|
|
key: key,
|
|
|
|
|
initialValue: value,
|
|
|
|
|
enabled: enabled,
|
|
|
|
|
onChanged: (v) {
|
|
|
|
|
onChanged(v);
|
|
|
|
|
_emit();
|
|
|
|
|
},
|
|
|
|
|
keyboardType: number
|
|
|
|
|
? const TextInputType.numberWithOptions(decimal: true, signed: true)
|
|
|
|
|
: TextInputType.text,
|
|
|
|
|
inputFormatters: number
|
|
|
|
|
? [FilteringTextInputFormatter.allow(RegExp(r'[0-9.,\-]'))]
|
|
|
|
|
: null,
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
fontWeight: bold ? FontWeight.w600 : FontWeight.normal,
|
|
|
|
|
),
|
|
|
|
|
decoration: const InputDecoration(
|
|
|
|
|
isDense: true,
|
|
|
|
|
contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _iconBtn(IconData icon, VoidCallback onTap) => IconButton(
|
|
|
|
|
onPressed: onTap,
|
|
|
|
|
icon: Icon(icon, size: 14),
|
|
|
|
|
color: const Color(0xFF94A3B8),
|
|
|
|
|
visualDensity: VisualDensity.compact,
|
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
|
constraints: const BoxConstraints(minWidth: 24, minHeight: 24),
|
|
|
|
|
);
|
2026-06-07 11:42:44 +02:00
|
|
|
}
|