feat(todo): a task's locations, in its payload and as quick add's + (ADR 0033, D32)

TaskLocation (name, address, position, optional OSM ID, reminder) goes in
the sealed payload as `locations`, schema still 1; recent places are read
from the tasks. parseQuickAdd takes `+name` of a place named before, the
longest name first, kept as text as any other token (D29); an unknown
`+word` stays text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-05 15:23:46 +01:00
commit 1db888a679
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -16,6 +16,11 @@ void main() {
];
const labels = [(id: 'l1', name: 'HalkyonToDo'), (id: 'l2', name: 'errand')];
const locations = [
(id: 'edeka', name: 'EDEKA'),
(id: 'koros', name: 'EDEKA Koros'),
];
ParsedTask parse(
String text, {
List<QuickAddWords> words = const [QuickAddWords.en],
@ -26,9 +31,45 @@ void main() {
words: words,
projects: projects,
labels: labels,
locations: locations,
ignored: ignored,
);
group('+location (D32)', () {
test('a place named before, the longest name, the case aside', () {
final added = parse('Shop +edeka koros tomorrow');
expect(added.title, 'Shop');
expect(added.locationIds, ['koros']);
expect(added.tokens.first.kind, QuickAddKind.location);
});
test('several, each once', () {
expect(parse('Shop +EDEKA +edeka +EDEKA Koros').locationIds, [
'edeka',
'koros',
]);
});
test("one not named before stays text: there's nothing to take", () {
final added = parse('Shop +Rewe');
expect(added.title, 'Shop +Rewe');
expect(added.locationIds, isEmpty);
});
test('a + inside a word is none', () {
expect(parse('a+EDEKA').locationIds, isEmpty);
});
test('kept as text where the person said so (D29), there alone', () {
final added = parse(
'Shop +EDEKA and +EDEKA',
ignored: const [(start: 5, end: 11)],
);
expect(added.title, 'Shop +EDEKA and');
expect(added.locationIds, ['edeka']);
});
});
group('symbols, in every language', () {
test('#project, the longest name matching, the case aside', () {
final added = parse('Clean Gutters #inbox');