feat(app): kanji and kana in the dictionary, beside the words
Where the instance holds the characters of a studyset's language, the dictionary screen has a tab for them, Kanji & kana: search by character, reading (kana or romaji) or meaning, and whole levels to add, under their names: the kana (hiragana, katakana), the JLPT levels and the school grades. A character becomes a character card, its meanings (a kana's romaji) and readings, tagged with its level (JLPT-N5), school grade (Grade 1 … Grade 6, Secondary school) and script (Hiragana, Katakana). A character card's Look up searches the characters, and an entry looked up again on a card swaps the tags the one before brought, as words do. A dictionary's entries are now words or characters (DictionaryItem), as its kind says. 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:
parent
2fc4205010
commit
cec518350a
1 changed files with 1034 additions and 158 deletions
|
|
@ -58,12 +58,36 @@ DictionaryWord word(
|
|||
senses: [VocabularySense(glosses: glosses, pos: pos)],
|
||||
);
|
||||
|
||||
/// A KANJIDIC2 character: [headword] meaning [meanings], read [on] and
|
||||
/// [kun], with [labels]; a kana with its [romaji].
|
||||
DictionaryCharacter character(
|
||||
String headword, {
|
||||
List<String> meanings = const [],
|
||||
List<String> on = const [],
|
||||
List<String> kun = const [],
|
||||
List<String> labels = const [],
|
||||
String? romaji,
|
||||
int? grade,
|
||||
int? strokes,
|
||||
}) => DictionaryCharacter(
|
||||
ref: (source: 'kanjidic', id: headword),
|
||||
headword: headword,
|
||||
labels: labels,
|
||||
meanings: meanings,
|
||||
onReadings: on,
|
||||
kunReadings: kun,
|
||||
romaji: romaji,
|
||||
grade: grade,
|
||||
strokes: strokes,
|
||||
);
|
||||
|
||||
/// A [DictionaryGateway] in memory: an instance with the dictionaries
|
||||
/// [available], each holding its [words] in their order. A search finds the words whose
|
||||
/// headword, reading or a meaning starts with the query.
|
||||
/// [available], holding the [words] (and characters) of each source in
|
||||
/// their order. A search finds the entries whose headword, reading, a
|
||||
/// meaning or a reading starts with the query.
|
||||
class FakeDictionaryGateway({
|
||||
final List<Dictionary> available = const [jmdict],
|
||||
final List<DictionaryWord> words = const [],
|
||||
final List<DictionaryItem> words = const [],
|
||||
}) implements DictionaryGateway {
|
||||
/// When set, every request fails with it.
|
||||
Exception? fail;
|
||||
|
|
@ -80,8 +104,12 @@ class FakeDictionaryGateway({
|
|||
return available;
|
||||
}
|
||||
|
||||
/// The entries of [dictionary].
|
||||
Iterable<DictionaryItem> _of(Dictionary dictionary) =>
|
||||
words.where((word) => word.ref.source == dictionary.source);
|
||||
|
||||
@override
|
||||
Future<List<DictionaryWord>> search(
|
||||
Future<List<DictionaryItem>> search(
|
||||
Dictionary dictionary,
|
||||
String query,
|
||||
) async {
|
||||
|
|
@ -90,29 +118,38 @@ class FakeDictionaryGateway({
|
|||
}
|
||||
final typed = query.trim().toLowerCase();
|
||||
return [
|
||||
for (final word in words)
|
||||
if ([
|
||||
word.headword,
|
||||
?word.reading,
|
||||
for (final sense in word.senses) ...sense.glosses,
|
||||
].any((key) => key.toLowerCase().startsWith(typed)))
|
||||
word,
|
||||
for (final item in _of(dictionary))
|
||||
if (switch (item) {
|
||||
DictionaryWord() => [
|
||||
item.headword,
|
||||
?item.reading,
|
||||
for (final sense in item.senses) ...sense.glosses,
|
||||
],
|
||||
DictionaryCharacter() => [
|
||||
item.headword,
|
||||
...item.meaningsShown,
|
||||
...item.onReadings,
|
||||
for (final reading in item.kunReadings) reading.replaceAll('.', ''),
|
||||
],
|
||||
}.any((key) => key.toLowerCase().startsWith(typed)))
|
||||
item,
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> countLabelled(Dictionary dictionary, String label) async =>
|
||||
words.where((word) => word.labels.contains(label)).length;
|
||||
_of(dictionary).where((word) => word.labels.contains(label)).length;
|
||||
|
||||
@override
|
||||
Future<List<DictionaryWord>> labelled(
|
||||
Future<List<DictionaryItem>> labelled(
|
||||
Dictionary dictionary,
|
||||
String label, {
|
||||
required int offset,
|
||||
required int limit,
|
||||
}) async => words
|
||||
.where((word) => word.labels.contains(label))
|
||||
.skip(offset)
|
||||
.take(limit)
|
||||
.toList();
|
||||
}) async =>
|
||||
_of(dictionary)
|
||||
.where((word) => word.labels.contains(label))
|
||||
.skip(offset)
|
||||
.take(limit)
|
||||
.toList();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue