import 'dart:io'; import 'dart:convert'; /// 影视条目模型 class Movie { final String id; final String title; // 影视名称 final String? posterPath; // 本地海报路径 final DateTime? releaseDate; // 上映时间 final List directors; // 导演列表 final List writers; // 编剧列表 final List actors; // 主演列表 final List genres; // 类型 final List alternateTitles; // 别名 final String? summary; // 剧情简介 final double? rating; // 评分 1-10 final String status; // watched/want_to_watch/watching final DateTime createdAt; final DateTime updatedAt; final bool isDeleted; Movie({ required this.id, required this.title, this.posterPath, this.releaseDate, this.directors = const [], this.writers = const [], this.actors = const [], this.genres = const [], this.alternateTitles = const [], this.summary, this.rating, required this.status, required this.createdAt, required this.updatedAt, this.isDeleted = false, }); factory Movie.fromJson(Map json) { return Movie( id: json['id'] ?? '', title: json['title'] ?? '', posterPath: json['poster_path'], releaseDate: json['release_date'] != null ? DateTime.parse(json['release_date']) : null, directors: _parseStringList(json['directors']), writers: _parseStringList(json['writers']), actors: _parseStringList(json['actors']), genres: _parseStringList(json['genres']), alternateTitles: _parseStringList(json['alternate_titles']), summary: json['summary'], rating: json['rating']?.toDouble(), status: json['status'] ?? 'want_to_watch', createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : DateTime.now(), updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : DateTime.now(), isDeleted: json['is_deleted'] == 1 || json['is_deleted'] == true, ); } Map toJson() { return { 'id': id, 'title': title, 'poster_path': posterPath, 'release_date': releaseDate?.toIso8601String(), 'directors': jsonEncode(directors), 'writers': jsonEncode(writers), 'actors': jsonEncode(actors), 'genres': jsonEncode(genres), 'alternate_titles': jsonEncode(alternateTitles), 'summary': summary, 'rating': rating, 'status': status, 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt.toIso8601String(), 'is_deleted': isDeleted ? 1 : 0, }; } /// 获取封面文件 File? get posterFile { if (posterPath == null || posterPath!.isEmpty) return null; return File(posterPath!); } /// 解析字符串列表(公共静态方法,供Book使用) static List parseStringList(dynamic data) { if (data == null) return []; if (data is List) { return data.map((e) => e.toString()).toList(); } if (data is String) { try { // 尝试解析JSON字符串 final decoded = jsonDecode(data); if (decoded is List) { return decoded.map((e) => e.toString()).toList(); } } catch (e) { // 如果解析失败,按逗号分割 return data.split(',').map((s) => s.trim()).where((s) => s.isNotEmpty).toList(); } } return []; } /// 解析字符串列表(私有别名,保持兼容性) static List _parseStringList(dynamic data) => parseStringList(data); /// 复制并修改 Movie copyWith({ String? id, String? title, String? posterPath, DateTime? releaseDate, List? directors, List? writers, List? actors, List? genres, List? alternateTitles, String? summary, double? rating, String? status, DateTime? createdAt, DateTime? updatedAt, bool? isDeleted, }) { return Movie( id: id ?? this.id, title: title ?? this.title, posterPath: posterPath ?? this.posterPath, releaseDate: releaseDate ?? this.releaseDate, directors: directors ?? this.directors, writers: writers ?? this.writers, actors: actors ?? this.actors, genres: genres ?? this.genres, alternateTitles: alternateTitles ?? this.alternateTitles, summary: summary ?? this.summary, rating: rating ?? this.rating, status: status ?? this.status, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, isDeleted: isDeleted ?? this.isDeleted, ); } } /// 书籍条目模型 class Book { final String id; final String title; // 书籍名称 final String? coverPath; // 本地封面路径 final List authors; // 作者列表 final List alternateTitles; // 别名 final String? publisher; // 出版社 final List genres; // 类型 final String? summary; // 书籍简介 final double? rating; // 评分 1-10 final String status; // read/reading/want_to_read final DateTime createdAt; final DateTime updatedAt; final bool isDeleted; Book({ required this.id, required this.title, this.coverPath, this.authors = const [], this.alternateTitles = const [], this.publisher, this.genres = const [], this.summary, this.rating, required this.status, required this.createdAt, required this.updatedAt, this.isDeleted = false, }); factory Book.fromJson(Map json) { return Book( id: json['id'] ?? '', title: json['title'] ?? '', coverPath: json['cover_path'], authors: Movie.parseStringList(json['authors']), alternateTitles: Movie.parseStringList(json['alternate_titles']), publisher: json['publisher'], genres: Movie.parseStringList(json['genres']), summary: json['summary'], rating: json['rating']?.toDouble(), status: json['status'] ?? 'want_to_read', createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : DateTime.now(), updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : DateTime.now(), isDeleted: json['is_deleted'] == 1 || json['is_deleted'] == true, ); } Map toJson() { return { 'id': id, 'title': title, 'cover_path': coverPath, 'authors': jsonEncode(authors), 'alternate_titles': jsonEncode(alternateTitles), 'publisher': publisher, 'genres': jsonEncode(genres), 'summary': summary, 'rating': rating, 'status': status, 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt.toIso8601String(), 'is_deleted': isDeleted ? 1 : 0, }; } /// 获取封面文件 File? get coverFile { if (coverPath == null || coverPath!.isEmpty) return null; return File(coverPath!); } /// 复制并修改 Book copyWith({ String? id, String? title, String? coverPath, List? authors, List? alternateTitles, String? publisher, List? genres, String? summary, double? rating, String? status, DateTime? createdAt, DateTime? updatedAt, bool? isDeleted, }) { return Book( id: id ?? this.id, title: title ?? this.title, coverPath: coverPath ?? this.coverPath, authors: authors ?? this.authors, alternateTitles: alternateTitles ?? this.alternateTitles, publisher: publisher ?? this.publisher, genres: genres ?? this.genres, summary: summary ?? this.summary, rating: rating ?? this.rating, status: status ?? this.status, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, isDeleted: isDeleted ?? this.isDeleted, ); } } /// 笔记模型 class Note { final String id; final String content; final String contentType; // markdown / rich_text final List tags; final DateTime createdAt; final DateTime updatedAt; Note({ required this.id, required this.content, this.contentType = 'markdown', this.tags = const [], required this.createdAt, required this.updatedAt, }); factory Note.fromJson(Map json) { return Note( id: json['id']?.toString() ?? '', content: json['content'] ?? '', contentType: json['content_type'] ?? 'markdown', tags: Movie.parseStringList(json['tags']), createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : DateTime.now(), updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : DateTime.now(), ); } Map toJson() { return { 'id': id, 'content': content, 'content_type': contentType, 'tags': jsonEncode(tags), 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt.toIso8601String(), }; } /// 复制并修改 Note copyWith({ String? id, String? content, String? contentType, List? tags, DateTime? createdAt, DateTime? updatedAt, }) { return Note( id: id ?? this.id, content: content ?? this.content, contentType: contentType ?? this.contentType, tags: tags ?? this.tags, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, ); } /// 获取内容摘要(前100字) String get summary { if (content.length <= 100) return content; return '${content.substring(0, 100)}...'; } }