readful/lib/models/highlight.dart
ddshi 02010ff972 feat: 完成数据持久化阶段并规划UI开发
📊 数据持久化阶段完成:
- 完成4个数据模型的Hive集成(Book, Bookshelf, Bookmark, Highlight)
- 实现4个Repository数据访问层
- 生成5个TypeAdapter自动序列化文件
- 完成所有模型的CRUD操作和测试验证

📚 项目文档更新:
- 新增数据持久化阶段完成总结文档
- 更新CLAUDE.md项目主文档
- 完善项目结构说明和开发进度

🚀 UI开发阶段规划:
- 定义产品定位:类似微信读书的Material Design电子书阅读器
- 制定4阶段开发计划:UI基础架构→顶部导航→首页内容→数据集成
- 明确页面结构:底部Tab导航(首页/书库/统计/我的)
- 规划核心功能:搜索、导入、最近阅读、摘录列表

🎯 下一里程碑:
- 开始UI基础架构搭建
- 实现底部Tab导航和Material Design主题系统

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 17:34:50 +08:00

258 lines
6.9 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:hive/hive.dart';
part 'highlight.g.dart';
///高亮模型
/// 不同颜色的高亮
@HiveType(typeId: 6)
enum HighlightColor {
@HiveField(0)
yellow, // 黄色 - 默认高亮
@HiveField(1)
orange, // 橙色 - 重要内容
@HiveField(2)
green, // 绿色 - 已理解内容
@HiveField(3)
blue, // 蓝色 - 需要复习
@HiveField(4)
pink // 粉色 - 个人感想
}
/// 批注类型枚举
/// 用于分类不同类型的批注内容
@HiveType(typeId: 7)
enum AnnotationType {
@HiveField(0)
note, // 笔记 - 记录知识点
@HiveField(1)
thought, // 感想 - 个人想法
@HiveField(2)
summary, // 摘要 - 内容总结
@HiveField(3)
question // 问题 - 疑问记录
}
///高亮模型
// 关联书籍和章节
// 记录选中的文本范围
// 支持不同颜色的高亮
// 记录创建时间
@HiveType(typeId: 8)
class Highlight {
//唯一标识符 - 使用UUID确保全局唯一
@HiveField(0)
final String id;
//对应的书籍id
@HiveField(1)
final String bookId;
// 对应章节id
@HiveField(2)
final String? chapterId;
// 选中文本
@HiveField(3)
final String selectedText;
// 开始索引
@HiveField(4)
final int startIndex;
// 结尾索引
@HiveField(5)
final int endIndex;
// 高亮颜色
@HiveField(6)
final HighlightColor color;
// 创建时间
@HiveField(7)
final DateTime createdTime;
/// 批注内容 - 可选字段,用于存储用户对高亮的注释
@HiveField(8)
final String? annotation;
/// 批注类型 - 可选字段,用于分类批注
@HiveField(9)
final AnnotationType? annotationType;
/// 批注添加时间 - 可选字段,记录批注的最后修改时间
@HiveField(10)
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)';
}
}