feat(jellyfin): any stretch of a line's characters chosen by hand
The cut takes the longest word and knows no grammar, so 今日は reads as こんにちは where it is 今日 and は. Any stretch of a line's characters can now be chosen by hand: dragged across with a mouse, Shift+clicked from the word or stretch chosen, or on a touch screen held on a character and dragged on. It is looked up as one word, as it stands or as a form of one, in one small request (the instance has the line's text already); while it is chosen the line reads it as that word (きょう over 今日), and what the dictionary lacks as one word is offered as a search on Jisho. The line's words move into line_words.dart, out of the Watch screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
9b5ea88a8a
commit
48ac84d92c
1 changed files with 918 additions and 209 deletions
|
|
@ -600,6 +600,98 @@ void main() {
|
|||
expect(card.content.entry, (source: 'jmdict', id: '37'));
|
||||
});
|
||||
|
||||
group('a stretch chosen by hand (decided 2026-10-13: by characters)', () {
|
||||
final greetings = [
|
||||
word('40', '今日', reading: 'きょう', pos: ['n'], glosses: ['today']),
|
||||
word('41', '今日は', reading: 'こんにちは', pos: ['int'], glosses: ['hello']),
|
||||
word('42', 'は', pos: ['prt'], labels: ['common']),
|
||||
word('43', '雨', reading: 'あめ', pos: ['n'], glosses: ['rain']),
|
||||
word('44', 'だ', pos: ['cop'], labels: ['common']),
|
||||
];
|
||||
Future<void> watchGreetings(WidgetTester tester) async {
|
||||
await watch(
|
||||
tester,
|
||||
vtt: {
|
||||
('episode-1', 2): 'WEBVTT\n\n00:00:01.000 --> 00:00:05.000\n今日は雨だ\n',
|
||||
('episode-1', 3):
|
||||
'WEBVTT\n\n00:00:01.000 --> 00:00:05.000\nA grey sky.\n',
|
||||
},
|
||||
words: greetings,
|
||||
);
|
||||
await playTo(tester, const Duration(seconds: 2));
|
||||
}
|
||||
|
||||
/// The middle of the [index]th character of the base text [text] of
|
||||
/// the line (four characters to a run at most here, each as wide).
|
||||
Offset character(WidgetTester tester, String text, int index) {
|
||||
final rect = tester.getRect(find.text(text, findRichText: true).first);
|
||||
final width = rect.width / text.length;
|
||||
return Offset(rect.left + width * (index + 0.5), rect.center.dy);
|
||||
}
|
||||
|
||||
testWidgets('dragged across with a mouse, the characters chosen are '
|
||||
'looked up as one word, also inside a word the cut took longer: '
|
||||
'今日 out of 今日は', (tester) async {
|
||||
await watchGreetings(tester);
|
||||
await players.last!.play();
|
||||
expect(find.text('今日', findRichText: true), findsOneWidget);
|
||||
|
||||
final drag = await tester.startGesture(
|
||||
character(tester, '今日', 0),
|
||||
kind: PointerDeviceKind.mouse,
|
||||
);
|
||||
await drag.moveTo(character(tester, '今日', 1));
|
||||
await drag.up();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(players.last!.state.value.playing, isFalse);
|
||||
expect(find.textContaining('today', findRichText: true), findsOneWidget);
|
||||
expect(find.textContaining('hello', findRichText: true), findsNothing);
|
||||
// While chosen, the line reads it as the word chosen: きょう, not
|
||||
// こんにち of こんにちは.
|
||||
expect(find.text('こんにち'), findsNothing);
|
||||
expect(find.text('きょう'), findsWidgets);
|
||||
});
|
||||
|
||||
testWidgets('Shift+click chooses from the word chosen to the character '
|
||||
'clicked; what the dictionary lacks as one word is searched on '
|
||||
'Jisho', (tester) async {
|
||||
await watchGreetings(tester);
|
||||
await tester.tap(find.text('雨', findRichText: true));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.textContaining('rain', findRichText: true), findsOneWidget);
|
||||
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft);
|
||||
final click = await tester.startGesture(
|
||||
character(tester, 'だ', 0),
|
||||
kind: PointerDeviceKind.mouse,
|
||||
);
|
||||
await click.up();
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.text("雨だ isn't in the dictionary as one word."),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Search Jisho for it'), findsOneWidget);
|
||||
expect(find.textContaining('rain', findRichText: true), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('on a phone, holding a character starts a stretch, and '
|
||||
'moving on extends it', (tester) async {
|
||||
await watchGreetings(tester);
|
||||
|
||||
final hold = await tester.startGesture(character(tester, '今日', 0));
|
||||
await tester.pump(const Duration(milliseconds: 600));
|
||||
await hold.moveTo(character(tester, '今日', 1));
|
||||
await hold.up();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.textContaining('today', findRichText: true), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets("the episode's words can be studied or crammed: the cards of "
|
||||
'its words, held before it was watched too, get its tag', (tester) async {
|
||||
final station = sampleWords.firstWhere((word) => word.headword == '駅');
|
||||
|
|
|
|||
Loading…
Reference in a new issue