fix(app): furigana stays on its word, and readings typed as learners type

Furigana:
- Text typed after a word with a reading no longer takes the reading.
- A reading over text formatted in parts (a bold kanji) is drawn once,
  over all of it, each part in its own style; in Markdown it is one
  <ruby>, the parts keeping their marks, the reading escaped.
- Readings follow the editor's text size, not the system's, and a
  linked word with a reading still opens its link.
- Anki's <ruby> keeps the formatting inside it.
- The Markdown export escapes what Markdown would read as its syntax
  and keeps blank lines inside code blocks.

Typing a reading:
- Hepburn as learners type it: onna is おんな, konnichiwa こんにちは, m
  before b, p and m is ん (shimbun); keyboards' n' and nnn still work.
- The caret stays where the person types, also in the middle.
- Macrons count both ways (ō as おう or おお); a card listing several
  readings (いく、ゆく) takes any of them; only words written with kanji
  ask for their reading.
- No autocorrect, suggestions or curly quotes in the field; Done with
  nothing typed keeps the keyboard; the lock screen lets go of the field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-09 12:45:19 +02:00
commit d5e5945d93
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -184,6 +184,24 @@ void main() {
{'insert': 'を読む'},
]);
});
test('formatting inside a ruby stays, with the reading over it', () {
final content = ankiContent([
'<ruby><b>漢</b>字<rt>かんじ</rt></ruby>',
], assetOf: files.get);
final document = content.editorJson['document']! as Map<String, Object?>;
final line = (document['children']! as List).single as Map;
expect((line['data']! as Map)['delta'], [
{
'insert': '漢',
'attributes': {'ruby': 'かんじ', 'bold': true},
},
{
'insert': '字',
'attributes': {'ruby': 'かんじ'},
},
]);
});
}
extension on Map<String, String> {