Files
Hirameki-SRS/lib/src/models/kanji_item.dart
2025-10-28 20:32:52 +01:00

172 lines
4.4 KiB
Dart

enum QuizMode { kanjiToEnglish, englishToKanji, reading }
class SrsItem {
final int kanjiId;
final QuizMode quizMode;
final String? readingType; // 'onyomi' or 'kunyomi'
int srsStage;
DateTime lastAsked;
SrsItem({
required this.kanjiId,
required this.quizMode,
this.readingType,
this.srsStage = 0,
DateTime? lastAsked,
}) : lastAsked = lastAsked ?? DateTime.now();
}
class KanjiItem {
final int id;
final int level;
final String characters;
final List<String> meanings;
final List<String> onyomi;
final List<String> kunyomi;
final Map<String, SrsItem> srsItems = {};
KanjiItem({
required this.id,
required this.level,
required this.characters,
required this.meanings,
required this.onyomi,
required this.kunyomi,
});
factory KanjiItem.fromSubject(Map<String, dynamic> subj) {
final int id = subj['id'] as int;
final data = subj['data'] as Map<String, dynamic>;
final int level = data['level'] as int;
final String characters = (data['characters'] ?? '') as String;
final List<String> meanings = <String>[];
final List<String> onyomi = <String>[];
final List<String> kunyomi = <String>[];
if (data['meanings'] != null) {
for (final m in data['meanings'] as List) {
meanings.add((m['meaning'] as String).toLowerCase());
}
}
if (data['readings'] != null) {
for (final r in data['readings'] as List) {
final typ = r['type'] as String? ?? '';
final reading = r['reading'] as String? ?? '';
if (typ == 'onyomi') {
onyomi.add(_katakanaToHiragana(reading));
} else if (typ == 'kunyomi') {
kunyomi.add(reading);
}
}
}
return KanjiItem(
id: id,
level: level,
characters: characters,
meanings: meanings,
onyomi: onyomi,
kunyomi: kunyomi,
);
}
}
String _katakanaToHiragana(String input) {
final buf = StringBuffer();
for (final r in input.runes) {
if (r >= 0x30A1 && r <= 0x30FA) {
buf.writeCharCode(r - 0x60);
} else {
buf.writeCharCode(r);
}
}
return buf.toString();
}
enum VocabQuizMode { vocabToEnglish, englishToVocab, audioToEnglish }
class VocabSrsItem {
final int vocabId;
final VocabQuizMode quizMode;
int srsStage;
DateTime lastAsked;
VocabSrsItem({
required this.vocabId,
required this.quizMode,
this.srsStage = 0,
DateTime? lastAsked,
}) : lastAsked = lastAsked ?? DateTime.now();
}
class PronunciationAudio {
final String url;
final String gender;
PronunciationAudio({required this.url, required this.gender});
}
class VocabularyItem {
final int id;
final int level;
final String characters;
final List<String> meanings;
final List<String> readings;
final List<PronunciationAudio> pronunciationAudios;
final Map<String, VocabSrsItem> srsItems = {};
VocabularyItem(
{required this.id,
required this.level,
required this.characters,
required this.meanings,
required this.readings,
required this.pronunciationAudios});
factory VocabularyItem.fromSubject(Map<String, dynamic> subj) {
final int id = subj['id'] as int;
final data = subj['data'] as Map<String, dynamic>;
final int level = data['level'] as int;
final String characters = (data['characters'] ?? '') as String;
final List<String> meanings = <String>[];
final List<String> readings = <String>[];
final List<PronunciationAudio> pronunciationAudios = <PronunciationAudio>[];
if (data['meanings'] != null) {
for (final m in data['meanings'] as List) {
meanings.add((m['meaning'] as String).toLowerCase());
}
}
if (data['readings'] != null) {
for (final r in data['readings'] as List) {
readings.add(r['reading'] as String);
}
}
if (data['pronunciation_audios'] != null) {
for (final audio in data['pronunciation_audios'] as List) {
final url = audio['url'] as String?;
final metadata = audio['metadata'] as Map<String, dynamic>?;
final gender = metadata?['gender'] as String?;
if (url != null && gender != null) {
pronunciationAudios.add(PronunciationAudio(
url: url,
gender: gender,
));
}
}
}
return VocabularyItem(
id: id,
level: level,
characters: characters,
meanings: meanings,
readings: readings,
pronunciationAudios: pronunciationAudios);
}
}