201 lines
4.8 KiB
Dart
201 lines
4.8 KiB
Dart
|
|
/// 发音练习项目数据模型
|
||
|
|
class PronunciationItem {
|
||
|
|
final String id;
|
||
|
|
final String text;
|
||
|
|
final String phonetic;
|
||
|
|
final String audioUrl;
|
||
|
|
final PronunciationType type;
|
||
|
|
final DifficultyLevel difficulty;
|
||
|
|
final String category;
|
||
|
|
final List<String> tips;
|
||
|
|
final DateTime createdAt;
|
||
|
|
|
||
|
|
PronunciationItem({
|
||
|
|
required this.id,
|
||
|
|
required this.text,
|
||
|
|
required this.phonetic,
|
||
|
|
required this.audioUrl,
|
||
|
|
required this.type,
|
||
|
|
required this.difficulty,
|
||
|
|
required this.category,
|
||
|
|
required this.tips,
|
||
|
|
required this.createdAt,
|
||
|
|
});
|
||
|
|
|
||
|
|
factory PronunciationItem.fromJson(Map<String, dynamic> json) {
|
||
|
|
return PronunciationItem(
|
||
|
|
id: json['id'],
|
||
|
|
text: json['text'],
|
||
|
|
phonetic: json['phonetic'],
|
||
|
|
audioUrl: json['audioUrl'],
|
||
|
|
type: PronunciationType.values.firstWhere(
|
||
|
|
(e) => e.toString().split('.').last == json['type'],
|
||
|
|
),
|
||
|
|
difficulty: DifficultyLevel.values.firstWhere(
|
||
|
|
(e) => e.toString().split('.').last == json['difficulty'],
|
||
|
|
),
|
||
|
|
category: json['category'],
|
||
|
|
tips: List<String>.from(json['tips']),
|
||
|
|
createdAt: DateTime.parse(json['createdAt']),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() {
|
||
|
|
return {
|
||
|
|
'id': id,
|
||
|
|
'text': text,
|
||
|
|
'phonetic': phonetic,
|
||
|
|
'audioUrl': audioUrl,
|
||
|
|
'type': type.toString().split('.').last,
|
||
|
|
'difficulty': difficulty.toString().split('.').last,
|
||
|
|
'category': category,
|
||
|
|
'tips': tips,
|
||
|
|
'createdAt': createdAt.toIso8601String(),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
PronunciationItem copyWith({
|
||
|
|
String? id,
|
||
|
|
String? text,
|
||
|
|
String? phonetic,
|
||
|
|
String? audioUrl,
|
||
|
|
PronunciationType? type,
|
||
|
|
DifficultyLevel? difficulty,
|
||
|
|
String? category,
|
||
|
|
List<String>? tips,
|
||
|
|
DateTime? createdAt,
|
||
|
|
}) {
|
||
|
|
return PronunciationItem(
|
||
|
|
id: id ?? this.id,
|
||
|
|
text: text ?? this.text,
|
||
|
|
phonetic: phonetic ?? this.phonetic,
|
||
|
|
audioUrl: audioUrl ?? this.audioUrl,
|
||
|
|
type: type ?? this.type,
|
||
|
|
difficulty: difficulty ?? this.difficulty,
|
||
|
|
category: category ?? this.category,
|
||
|
|
tips: tips ?? this.tips,
|
||
|
|
createdAt: createdAt ?? this.createdAt,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 发音练习类型
|
||
|
|
enum PronunciationType {
|
||
|
|
word,
|
||
|
|
sentence,
|
||
|
|
phrase,
|
||
|
|
phoneme,
|
||
|
|
}
|
||
|
|
|
||
|
|
extension PronunciationTypeExtension on PronunciationType {
|
||
|
|
String get displayName {
|
||
|
|
switch (this) {
|
||
|
|
case PronunciationType.word:
|
||
|
|
return '单词发音';
|
||
|
|
case PronunciationType.sentence:
|
||
|
|
return '句子朗读';
|
||
|
|
case PronunciationType.phrase:
|
||
|
|
return '短语练习';
|
||
|
|
case PronunciationType.phoneme:
|
||
|
|
return '音素练习';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
String get description {
|
||
|
|
switch (this) {
|
||
|
|
case PronunciationType.word:
|
||
|
|
return '练习单个单词的准确发音';
|
||
|
|
case PronunciationType.sentence:
|
||
|
|
return '练习完整句子的语调和节奏';
|
||
|
|
case PronunciationType.phrase:
|
||
|
|
return '练习常用短语的连读';
|
||
|
|
case PronunciationType.phoneme:
|
||
|
|
return '练习基础音素的发音';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
String get icon {
|
||
|
|
switch (this) {
|
||
|
|
case PronunciationType.word:
|
||
|
|
return '🔤';
|
||
|
|
case PronunciationType.sentence:
|
||
|
|
return '📝';
|
||
|
|
case PronunciationType.phrase:
|
||
|
|
return '💬';
|
||
|
|
case PronunciationType.phoneme:
|
||
|
|
return '🔊';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 难度级别
|
||
|
|
enum DifficultyLevel {
|
||
|
|
beginner,
|
||
|
|
intermediate,
|
||
|
|
advanced,
|
||
|
|
}
|
||
|
|
|
||
|
|
extension DifficultyLevelExtension on DifficultyLevel {
|
||
|
|
String get displayName {
|
||
|
|
switch (this) {
|
||
|
|
case DifficultyLevel.beginner:
|
||
|
|
return '初级';
|
||
|
|
case DifficultyLevel.intermediate:
|
||
|
|
return '中级';
|
||
|
|
case DifficultyLevel.advanced:
|
||
|
|
return '高级';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
String get code {
|
||
|
|
switch (this) {
|
||
|
|
case DifficultyLevel.beginner:
|
||
|
|
return 'A1-A2';
|
||
|
|
case DifficultyLevel.intermediate:
|
||
|
|
return 'B1-B2';
|
||
|
|
case DifficultyLevel.advanced:
|
||
|
|
return 'C1-C2';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 发音练习记录
|
||
|
|
class PronunciationRecord {
|
||
|
|
final String id;
|
||
|
|
final String itemId;
|
||
|
|
final double score;
|
||
|
|
final String feedback;
|
||
|
|
final DateTime practiceDate;
|
||
|
|
final int attempts;
|
||
|
|
|
||
|
|
PronunciationRecord({
|
||
|
|
required this.id,
|
||
|
|
required this.itemId,
|
||
|
|
required this.score,
|
||
|
|
required this.feedback,
|
||
|
|
required this.practiceDate,
|
||
|
|
required this.attempts,
|
||
|
|
});
|
||
|
|
|
||
|
|
factory PronunciationRecord.fromJson(Map<String, dynamic> json) {
|
||
|
|
return PronunciationRecord(
|
||
|
|
id: json['id'],
|
||
|
|
itemId: json['itemId'],
|
||
|
|
score: json['score'].toDouble(),
|
||
|
|
feedback: json['feedback'],
|
||
|
|
practiceDate: DateTime.parse(json['practiceDate']),
|
||
|
|
attempts: json['attempts'],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() {
|
||
|
|
return {
|
||
|
|
'id': id,
|
||
|
|
'itemId': itemId,
|
||
|
|
'score': score,
|
||
|
|
'feedback': feedback,
|
||
|
|
'practiceDate': practiceDate.toIso8601String(),
|
||
|
|
'attempts': attempts,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|