主要功能: - ✅ 完成4个核心数据模型(Book、Highlight、Bookmark、Bookshelf) - ✅ 实现7个枚举类型,提供类型安全的数据分类 - ✅ 建立完整的数据模型设计标准和最佳实践 - ✅ 创建5篇详细学习文档,涵盖Flutter数据模型开发 技术成就: - 不可变对象设计模式 mastered - 空值安全语法熟练应用 - 工厂构造函数模式实践 - 序列化/反序列化机制完整实现 - 计算属性和便利方法优化 业务价值: - 完整支持电子书管理需求 - 高亮+批注功能集成设计 - 灵活的书架分类系统 - 可扩展的数据架构设计 文档体系: - 📚 项目概览和技术架构(CLAUDE.md) - 📓 数据模型完成度检查报告 - 📖 阶段性学习成果总结 - 💡 Flutter开发最佳实践指导 代码统计: - 4个核心模型文件,约1200行代码 - 7个枚举类型,45个数据字段 - 80+个方法,完整的对象生命周期管理 下一阶段:Hive数据库集成和Repository模式实现 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
224 lines
6.5 KiB
Dart
224 lines
6.5 KiB
Dart
///高亮模型
|
||
|
||
/// 不同颜色的高亮
|
||
enum HighlightColor {
|
||
yellow, // 黄色 - 默认高亮
|
||
orange, // 橙色 - 重要内容
|
||
green, // 绿色 - 已理解内容
|
||
blue, // 蓝色 - 需要复习
|
||
pink // 粉色 - 个人感想
|
||
}
|
||
|
||
/// 批注类型枚举
|
||
/// 用于分类不同类型的批注内容
|
||
enum AnnotationType {
|
||
note, // 笔记 - 记录知识点
|
||
thought, // 感想 - 个人想法
|
||
summary, // 摘要 - 内容总结
|
||
question // 问题 - 疑问记录
|
||
}
|
||
|
||
///高亮模型
|
||
// 关联书籍和章节
|
||
// 记录选中的文本范围
|
||
// 支持不同颜色的高亮
|
||
// 记录创建时间
|
||
class Highlight {
|
||
//唯一标识符 - 使用UUID确保全局唯一
|
||
final String id;
|
||
|
||
//对应的书籍id
|
||
final String bookId;
|
||
|
||
// 对应章节id
|
||
final String? chapterId;
|
||
|
||
// 选中文本
|
||
final String selectedText;
|
||
|
||
// 开始索引
|
||
final int startIndex;
|
||
|
||
// 结尾索引
|
||
final int endIndex;
|
||
|
||
// 高亮颜色
|
||
final HighlightColor color;
|
||
|
||
// 创建时间
|
||
final DateTime createdTime;
|
||
|
||
/// 批注内容 - 可选字段,用于存储用户对高亮的注释
|
||
final String? annotation;
|
||
|
||
/// 批注类型 - 可选字段,用于分类批注
|
||
final AnnotationType? annotationType;
|
||
|
||
/// 批注添加时间 - 可选字段,记录批注的最后修改时间
|
||
final DateTime? annotationTime;
|
||
|
||
const Highlight({
|
||
required this.id,
|
||
required this.bookId,
|
||
this.chapterId,
|
||
required this.selectedText,
|
||
required this.startIndex,
|
||
required this.endIndex,
|
||
required this.color,
|
||
required this.createdTime,
|
||
this.annotation, // 批注内容
|
||
this.annotationType, // 批注类型
|
||
this.annotationTime, // 批注时间
|
||
});
|
||
|
||
/// copyWith方法 - 创建对象的副本
|
||
Highlight copyWith({
|
||
String? id,
|
||
String? bookId,
|
||
String? chapterId,
|
||
String? selectedText,
|
||
int? startIndex,
|
||
int? endIndex,
|
||
HighlightColor? color,
|
||
DateTime? createdTime,
|
||
String? annotation,
|
||
AnnotationType? annotationType,
|
||
DateTime? annotationTime,
|
||
}) {
|
||
return Highlight(
|
||
id: id ?? this.id,
|
||
bookId: bookId ?? this.bookId,
|
||
chapterId: chapterId ?? this.chapterId,
|
||
selectedText: selectedText ?? this.selectedText,
|
||
startIndex: startIndex ?? this.startIndex,
|
||
endIndex: endIndex ?? this.endIndex,
|
||
color: color ?? this.color,
|
||
createdTime: createdTime ?? this.createdTime,
|
||
annotation: annotation ?? this.annotation,
|
||
annotationType: annotationType ?? this.annotationType,
|
||
annotationTime: annotationTime ?? this.annotationTime,
|
||
);
|
||
}
|
||
|
||
/// toMap方法 - 将对象转换为Map
|
||
Map<String, dynamic> toMap() {
|
||
return {
|
||
'id': id,
|
||
'bookId': bookId,
|
||
'chapterId': chapterId,
|
||
'selectedText': selectedText,
|
||
'startIndex': startIndex,
|
||
'endIndex': endIndex,
|
||
'color': color.name, // 枚举值转换为字符串
|
||
'createdTime': createdTime.toIso8601String(), // DateTime转换为字符串
|
||
'annotation': annotation,
|
||
'annotationType': annotationType?.name, // 枚举转换为字符串,注意可能是null
|
||
'annotationTime': annotationTime?.toIso8601String(), // DateTime转换为字符串,注意可能是null
|
||
};
|
||
}
|
||
|
||
/// fromMap构造函数 - 从Map创建Highlight对象
|
||
factory Highlight.fromMap(Map<String, dynamic> map) {
|
||
return Highlight(
|
||
id: map['id'],
|
||
bookId: map['bookId'],
|
||
chapterId: map['chapterId'],
|
||
selectedText: map['selectedText'],
|
||
startIndex: map['startIndex'],
|
||
endIndex: map['endIndex'],
|
||
color: HighlightColor.values.firstWhere((e) => e.name == map['color']),
|
||
createdTime: DateTime.parse(map['createdTime']),
|
||
annotation: map['annotation'], // 批注内容直接取值
|
||
annotationType: map['annotationType'] != null
|
||
? AnnotationType.values.firstWhere((e) => e.name == map['annotationType'])
|
||
: null, // 处理可选的枚举字段
|
||
annotationTime: map['annotationTime'] != null
|
||
? DateTime.parse(map['annotationTime'])
|
||
: null, // 处理可选的DateTime字段
|
||
);
|
||
}
|
||
|
||
/// 创建一个新Highlight实例的工厂方法
|
||
/// 这是一个便利方法,用于创建基本的高亮对象
|
||
/// 通常在用户选中文本时使用
|
||
factory Highlight.create({
|
||
required String bookId,
|
||
required String selectedText,
|
||
required int startIndex,
|
||
required int endIndex,
|
||
HighlightColor color = HighlightColor.yellow, // 默认颜色
|
||
String? chapterId,
|
||
}) {
|
||
return Highlight(
|
||
id: _generateId(), // 生成唯一ID
|
||
bookId: bookId,
|
||
chapterId: chapterId,
|
||
selectedText: selectedText,
|
||
startIndex: startIndex,
|
||
endIndex: endIndex,
|
||
color: color,
|
||
createdTime: DateTime.now(), // 当前时间作为创建时间
|
||
);
|
||
}
|
||
|
||
/// 生成唯一ID的私有方法
|
||
static String _generateId() {
|
||
return '${DateTime.now().millisecondsSinceEpoch}_${(DateTime.now().microsecond).toString()}';
|
||
}
|
||
|
||
/// 重写equals和hashCode,用于对象比较
|
||
@override
|
||
bool operator ==(Object other) {
|
||
if (identical(this, other)) return true;
|
||
return other is Highlight && other.id == id;
|
||
}
|
||
|
||
@override
|
||
int get hashCode => id.hashCode;
|
||
|
||
/// 计算属性:检查是否有批注
|
||
bool get hasAnnotation => annotation != null && annotation!.isNotEmpty;
|
||
|
||
/// 计算属性:获取批注文本长度
|
||
int get annotationLength => annotation?.length ?? 0;
|
||
|
||
/// 添加批注的方法
|
||
/// 返回一个新的Highlight对象,包含指定的批注内容
|
||
Highlight addAnnotation(String content, AnnotationType type) {
|
||
return copyWith(
|
||
annotation: content,
|
||
annotationType: type,
|
||
annotationTime: DateTime.now(), // 设置当前时间为批注时间
|
||
);
|
||
}
|
||
|
||
/// 更新批注内容的方法
|
||
/// 返回一个新的Highlight对象,包含更新的批注内容
|
||
Highlight updateAnnotation(String content, AnnotationType type) {
|
||
return copyWith(
|
||
annotation: content,
|
||
annotationType: type,
|
||
annotationTime: DateTime.now(), // 更新批注时间
|
||
);
|
||
}
|
||
|
||
/// 移除批注的方法
|
||
/// 返回一个新的Highlight对象,移除所有批注相关字段
|
||
Highlight removeAnnotation() {
|
||
return copyWith(
|
||
annotation: null,
|
||
annotationType: null,
|
||
annotationTime: null,
|
||
);
|
||
}
|
||
|
||
/// 重写toString方法,增加批注信息显示
|
||
@override
|
||
String toString() {
|
||
final annotationInfo = hasAnnotation
|
||
? ' [批注: $annotation]'
|
||
: '';
|
||
return 'Highlight(id: $id, bookId: $bookId, text: "$selectedText"$annotationInfo)';
|
||
}
|
||
}
|