fix(todo): quick add highlights a word while the keyboard still composes it

On Android, keyboards with suggestions (Gboard) and Japanese ones keep
the word being typed composing until a space. The title's controller
fell back to the plain composing span whenever a composing range was
set, so "today" lit up only after the space or once the keyboard
closed. It now always draws the tokens' highlight, cut where a token or
the composing range starts or ends, with the composing underline on top
where they overlap.

Whats-New: Add task highlights dates and other words as you type them, not only after a space.
Whats-New-De: „Aufgabe hinzufügen“ hebt Daten und andere Wörter schon beim Tippen hervor, nicht erst nach einem Leerzeichen.

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-04 22:16:10 +01:00
commit 0f8a559d2e
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -1463,6 +1463,43 @@ void main() {
expect(stored.single.content?.date, isNull);
});
testWidgets('a token is highlighted while the keyboard still composes '
'it, the composing underline over it (Gboard, Japanese IMEs)', (
tester,
) async {
await start(tester, usedBefore: true);
await goTab(tester, 'Inbox');
await tester.tap(find.byTooltip('Add task'));
await tester.pumpAndSettle();
await tester.showKeyboard(find.byKey(quickAddTitleKey));
const text = 'Pay rent today';
tester.testTextInput.updateEditingValue(
const TextEditingValue(
text: text,
selection: TextSelection.collapsed(offset: text.length),
composing: TextRange(start: 9, end: text.length),
),
);
await tester.pumpAndSettle();
final field = find.byKey(quickAddTitleKey);
final span = tester
.widget<TextField>(field)
.controller!
.buildTextSpan(
context: tester.element(field),
withComposing: true,
);
final today = span.children!.cast<TextSpan>().singleWhere(
(child) => child.text == 'today',
);
expect(today.style?.backgroundColor, isNotNull, reason: 'highlighted');
expect(today.style?.decoration, TextDecoration.underline);
final rest = span.children!.cast<TextSpan>().first;
expect(rest.text, 'Pay rent ');
expect(rest.style?.decoration, isNull);
});
testWidgets('a chip picked takes its token out of the title; the down '
'arrow and the + open the description', (tester) async {
await start(tester, usedBefore: true);