readful/lib/models/bookmark.dart
ddshi 7d7618401a feat: 完成数据模型设计阶段和学习文档整理
主要功能:
-  完成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>
2025-11-18 19:33:17 +08:00

157 lines
4.3 KiB
Dart
Raw 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.

/// 书签模型
/// 用于记录和管理阅读位置标记
class Bookmark {
final String id;
final String bookId;
final String? chapterId;
final String title;
final String? description;
final int pageIndex;
final double position; // 0.0-1.0之间的值,表示在文档中的相对位置
final String? previewText;
final DateTime createdTime;
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构造函数 - 从Map创建Book对象
///
/// 这是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;
}