feat(todo): quick add suggests projects and labels as # and @ are typed (ADR 0033, D15)
Up to five projects or labels whose name, or a word of it, starts with what follows the symbol show below the title; one tapped completes it. None for a symbol inside a word (C#), nor once a name is typed whole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
36f1e9a25c
commit
7fe74ed0d5
1 changed files with 187 additions and 18 deletions
|
|
@ -8,7 +8,9 @@ import 'package:halkyon_todo_flutter/src/app/todo_app.dart';
|
|||
import 'package:halkyon_todo_flutter/src/app/todo_dependencies.dart';
|
||||
import 'package:halkyon_todo_flutter/src/core/privacy/todo_keys.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/label/data/label_repository.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/label/model/label.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/project/data/project_repository.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/project/model/project.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/section/data/section_repository.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/section/model/section.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/task/data/task_repository.dart';
|
||||
|
|
@ -403,6 +405,71 @@ void main() {
|
|||
expect(content.labelIds, [labels.single.id]);
|
||||
});
|
||||
|
||||
testWidgets('# and @ suggest projects and labels as they are typed; '
|
||||
'one tapped completes the name', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
final shopping = await tester.runAsync(
|
||||
() => ProjectRepository(
|
||||
projectRows,
|
||||
keys,
|
||||
).save(const ProjectContent(name: 'Shopping', position: 1)),
|
||||
);
|
||||
projectRows.bringRemoteChanges();
|
||||
final errand = await tester.runAsync(
|
||||
() => LabelRepository(
|
||||
labelRows,
|
||||
keys,
|
||||
).add(const LabelContent(name: 'errand')),
|
||||
);
|
||||
labelRows.bringRemoteChanges();
|
||||
await goTab(tester, 'Inbox');
|
||||
await open(tester, 'Buy milk #sho');
|
||||
|
||||
final suggestion = find.widgetWithText(ListTile, 'Shopping');
|
||||
expect(suggestion, findsOneWidget);
|
||||
await tester.tap(suggestion);
|
||||
await tester.pumpAndSettle();
|
||||
final title = tester
|
||||
.widget<TextField>(find.byKey(quickAddTitleKey))
|
||||
.controller!;
|
||||
expect(title.text, 'Buy milk #Shopping ');
|
||||
expect(suggestion, findsNothing, reason: 'done with');
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(quickAddTitleKey),
|
||||
'${title.text}@er',
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.widgetWithText(ListTile, 'errand'));
|
||||
await tester.pumpAndSettle();
|
||||
await add(tester);
|
||||
|
||||
final stored = await tester.runAsync(() => tasks().all());
|
||||
final content = stored!.single.content!;
|
||||
expect(content.title, 'Buy milk');
|
||||
expect(content.projectId, shopping);
|
||||
expect(content.labelIds, [errand]);
|
||||
});
|
||||
|
||||
testWidgets('nothing is suggested for a # inside a word, nor where no '
|
||||
'name matches', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await tester.runAsync(
|
||||
() => ProjectRepository(
|
||||
projectRows,
|
||||
keys,
|
||||
).save(const ProjectContent(name: 'Shopping', position: 1)),
|
||||
);
|
||||
projectRows.bringRemoteChanges();
|
||||
await goTab(tester, 'Inbox');
|
||||
|
||||
await open(tester, 'Fix C#sho');
|
||||
expect(find.widgetWithText(ListTile, 'Shopping'), findsNothing);
|
||||
await tester.enterText(find.byKey(quickAddTitleKey), 'Fix #zz');
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(quickAddSuggestionsKey), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('a token tapped stays text', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await goTab(tester, 'Inbox');
|
||||
|
|
|
|||
Loading…
Reference in a new issue