📊 数据持久化阶段完成: - 完成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>
181 lines
4.5 KiB
Dart
181 lines
4.5 KiB
Dart
import 'package:hive/hive.dart';
|
||
|
||
part 'bookmark.g.dart';
|
||
|
||
/// 书签模型
|
||
/// 用于记录和管理阅读位置标记
|
||
@HiveType(typeId: 5)
|
||
class Bookmark {
|
||
@HiveField(0)
|
||
final String id;
|
||
|
||
@HiveField(1)
|
||
final String bookId;
|
||
|
||
@HiveField(2)
|
||
final String? chapterId;
|
||
|
||
@HiveField(3)
|
||
final String title;
|
||
|
||
@HiveField(4)
|
||
final String? description;
|
||
|
||
@HiveField(5)
|
||
final int pageIndex;
|
||
|
||
@HiveField(6)
|
||
final double position; // 0.0-1.0之间的值,表示在文档中的相对位置
|
||
|
||
@HiveField(7)
|
||
final String? previewText;
|
||
|
||
@HiveField(8)
|
||
final DateTime createdTime;
|
||
|
||
@HiveField(9)
|
||
final int sortOrder;
|
||
|
||
// 构造函数...
|
||
const Bookmark(
|
||
{required this.id,
|
||
required this.bookId,
|
||
this.chapterId,
|
||
required this.title,
|
||
this.description,
|
||
required this.pageIndex,
|
||
required this.position,
|
||
this.previewText,
|
||
required this.createdTime,
|
||
required this.sortOrder});
|
||
|
||
// copyWith方法...
|
||
Bookmark copyWith(
|
||
{String? id,
|
||
String? bookId,
|
||
String? chapterId,
|
||
String? title,
|
||
String? description,
|
||
int? pageIndex,
|
||
double? position,
|
||
String? previewText,
|
||
DateTime? createdTime,
|
||
int? sortOrder}) {
|
||
return Bookmark(
|
||
id: id ?? this.id, // 如果id不为null就使用新值,否则保持原值
|
||
bookId: bookId ?? this.bookId,
|
||
chapterId: chapterId ?? this.chapterId,
|
||
title: title ?? this.title,
|
||
description: description ?? this.description,
|
||
pageIndex: pageIndex ?? this.pageIndex,
|
||
position: position ?? this.position,
|
||
previewText: previewText ?? this.previewText,
|
||
createdTime: createdTime ?? this.createdTime,
|
||
sortOrder: sortOrder ?? this.sortOrder);
|
||
}
|
||
|
||
// toMap/fromMap方法...
|
||
/// toMap方法 - 将对象转换为Map
|
||
Map<String, dynamic> toMap() {
|
||
return {
|
||
'id': id,
|
||
'bookId': bookId,
|
||
'chapterId': chapterId,
|
||
'title': title,
|
||
'description': description,
|
||
'pageIndex': pageIndex,
|
||
'position': position,
|
||
'previewText': previewText,
|
||
'createdTime': createdTime.toIso8601String(),
|
||
'sortOrder': sortOrder
|
||
};
|
||
}
|
||
|
||
/// fromMap构造函数
|
||
///
|
||
/// 这是toMap的逆操作,用于:
|
||
/// 1. 从本地存储中读取数据
|
||
/// 2. 从网络请求中解析数据
|
||
/// 3. 从保存的状态中恢复对象
|
||
factory Bookmark.fromMap(Map<String, dynamic> map) {
|
||
return Bookmark(
|
||
id: map['id'],
|
||
bookId: map['bookId'],
|
||
chapterId: map['chapterId'],
|
||
title: map['title'],
|
||
description: map['description'],
|
||
pageIndex: map['pageIndex'],
|
||
position: map['position'],
|
||
previewText: map['previewText'],
|
||
createdTime: DateTime.parse(map['createdTime']),
|
||
sortOrder: map['sortOrder']);
|
||
}
|
||
|
||
// 工厂方法...
|
||
factory Bookmark.create({
|
||
required String bookId,
|
||
required String title,
|
||
required int pageIndex,
|
||
required double position,
|
||
String? chapterId,
|
||
String? description,
|
||
String? previewText,
|
||
}) {
|
||
return Bookmark(
|
||
id: _generateId(), // 生成唯一ID
|
||
bookId: bookId,
|
||
chapterId: chapterId,
|
||
title: title,
|
||
pageIndex: pageIndex,
|
||
position: position,
|
||
description: description,
|
||
previewText: previewText,
|
||
createdTime: DateTime.now(),
|
||
sortOrder: 0);
|
||
}
|
||
|
||
// 计算属性和实用方法...
|
||
/// 生成唯一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 Bookmark && other.id == id;
|
||
}
|
||
|
||
@override
|
||
int get hashCode => id.hashCode;
|
||
|
||
/// 重写toString方法,便于调试
|
||
@override
|
||
String toString() {
|
||
return 'Bookmark(id: $id, title: $title, bookId: $bookId, sortOrder: $sortOrder)';
|
||
}
|
||
|
||
// 更新位置
|
||
Bookmark updatePosition(int newPageIndex, double newPosition) {
|
||
return copyWith(
|
||
pageIndex: newPageIndex,
|
||
position: newPosition,
|
||
);
|
||
}
|
||
|
||
// 更新标题和描述
|
||
Bookmark updateInfo({String? title, String? description}) {
|
||
return copyWith(
|
||
title: title ?? this.title,
|
||
description: description ?? this.description,
|
||
);
|
||
}
|
||
|
||
// 格式化位置显示
|
||
String get positionDisplay => '${(position * 100).toInt()}%';
|
||
|
||
// 检查位置是否有效
|
||
bool get isValidPosition => position >= 0.0 && position <= 1.0;
|
||
}
|