fix(learn): a passage's gaps flow inside its text

A passage was a Wrap of a Text per part between gaps. A Wrap places whole
children, so a part longer than a line took the width to itself, and every
gap and the text after it started a line of its own. One Text.rich with each
gap a WidgetSpan wraps the text as one paragraph, the gaps standing in it.

Whats-New: Fill-in-the-blank passages read as running text, their gaps inside the lines.
Whats-New-De: Lückentexte lesen sich als fortlaufender Text, die Lücken stehen in den Zeilen.

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-11 15:44:51 +01:00
commit b45cb0f3cb
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -948,6 +948,47 @@ void main() {
expect(find.text('Correct!'), findsOneWidget);
});
testWidgets('a passage is one paragraph, its gaps standing in its lines; '
'a filled gap tapped gives its word back', (tester) async {
final paths = repository();
final id = await paths.createPath(
'japanese',
LearningPathContent.titled('Particles'),
);
await paths.createStep(
id,
StepKind.fillInTheBlank,
step(
StepKind.fillInTheBlank,
'Fill in',
const FillInTheBlank(passage: '私___学生です。', blanks: ['は']),
),
);
await showApp(tester, RoutePaths.path('japanese', id));
final passage = find.byWidgetPredicate(
(widget) =>
widget is RichText && widget.text.toPlainText().startsWith('私'),
);
expect(passage, findsOneWidget);
expect(
(tester.widget<RichText>(passage).text as TextSpan).toPlainText(),
contains('学生です。'),
reason: 'the text after the gap is in the same paragraph',
);
final inPassage = find.descendant(of: passage, matching: find.text('は'));
await tester.tap(find.widgetWithText(ActionChip, 'は'));
await tester.pumpAndSettle();
expect(inPassage, findsOneWidget);
expect(find.text('は'), findsOneWidget, reason: 'gone from the words');
await tester.tap(inPassage);
await tester.pumpAndSettle();
expect(inPassage, findsNothing);
expect(find.text('は'), findsOneWidget, reason: 'back among the words');
});
testWidgets('sorts items by tapping one and then its category', (
tester,
) async {