Files
ReelShort/lib/core/data/models/drama.dart
T
Vicky 77d5748dbb chore(client): 归档原型阶段未提交改动(binding/logic/view 分层与各页迭代)
为什么:客户端原型在 14d7bd3 之后又做了一轮(页面分层、发现页、分类滑动、播放器控件等),
一直留在工作区没入库。下一批账号链路要改其中的 app.dart / home_view / player_view / mine_view,
先归档这批既存改动,本批的实际 diff 才说得清边界。

只归档,不改行为:当前工作区 flutter analyze 0 问题、flutter test 148 全过。
2026-10-15 17:53:27 +08:00

126 lines
3.8 KiB
Dart

/// 短剧与剧集,字段与后端 `/app/**` 的下发结构对应。
///
/// 封面与播放地址都是后端返回的相对路径(`/files/...`),
/// 渲染前用 `AppConfig.mediaUrl` 补上服务地址。
class Episode {
const Episode({
required this.id,
required this.number,
required this.title,
required this.isFree,
this.videoUrl = '',
this.durationSec = 0,
this.locked = false,
});
final String id;
final int number;
final String title;
final bool isFree;
/// 播放地址:详情接口不下发,由 `/app/episodes/{id}/play` 返回后写入。
final String videoUrl;
final int durationSec;
/// 后端判定需要解锁;解锁能力(金币/VIP)在 M3 接入。
final bool locked;
Episode withVideoUrl(String url) => Episode(
id: id,
number: number,
title: title,
isFree: isFree,
videoUrl: url,
durationSec: durationSec,
locked: locked,
);
factory Episode.fromJson(Map<String, dynamic> json) {
return Episode(
id: (json['id'] ?? '').toString(),
number: (json['number'] as num?)?.toInt() ?? 0,
title: json['title'] as String? ?? '',
isFree: json['isFree'] == true,
durationSec: (json['durationSec'] as num?)?.toInt() ?? 0,
locked: json['locked'] == true,
videoUrl: json['playUrl'] as String? ?? '',
);
}
}
class Drama {
const Drama({
required this.id,
required this.title,
required this.synopsis,
required this.posterUrl,
this.episodes = const [],
this.category = '',
this.genre = '',
this.totalEpisodes = 0,
this.freeEpisodes = 0,
this.isHot = false,
this.viewCount = 0,
this.detailLoaded = false,
});
final String id;
final String title;
final String synopsis;
final String posterUrl;
final List<Episode> episodes;
final String category;
final String genre;
final int totalEpisodes;
final int freeEpisodes;
final bool isHot;
final int viewCount;
/// 详情接口是否已经取过完整剧集列表。
/// 列表卡片只带一集可播预览,需要完整剧集时再进详情。
final bool detailLoaded;
/// 卡片只带一集预览,集数以后端给的总集数为准。
int get episodeCount => totalEpisodes > 0 ? totalEpisodes : episodes.length;
/// 列表卡片:带一集可播预览(首页直接起播),完整剧集进详情再取。
factory Drama.fromCardJson(Map<String, dynamic> json) {
final preview = json['preview'];
return Drama(
id: (json['id'] ?? '').toString(),
title: json['title'] as String? ?? '',
synopsis: json['synopsis'] as String? ?? '',
posterUrl: json['cover'] as String? ?? '',
episodes: preview is Map<String, dynamic>
? [Episode.fromJson(preview)]
: const [],
category: json['category'] as String? ?? '',
genre: json['genre'] as String? ?? '',
totalEpisodes: (json['totalEpisodes'] as num?)?.toInt() ?? 0,
isHot: json['isHot'] == true,
viewCount: (json['viewCount'] as num?)?.toInt() ?? 0,
);
}
/// 详情:带剧集列表。
factory Drama.fromDetailJson(Map<String, dynamic> json) {
return Drama(
id: (json['id'] ?? '').toString(),
title: json['title'] as String? ?? '',
synopsis: json['synopsis'] as String? ?? '',
posterUrl: json['cover'] as String? ?? '',
category: json['category'] as String? ?? '',
genre: json['genre'] as String? ?? '',
totalEpisodes: (json['totalEpisodes'] as num?)?.toInt() ?? 0,
freeEpisodes: (json['freeEpisodes'] as num?)?.toInt() ?? 0,
isHot: json['isHot'] == true,
viewCount: (json['viewCount'] as num?)?.toInt() ?? 0,
detailLoaded: true,
episodes: (json['episodes'] as List? ?? const [])
.whereType<Map<String, dynamic>>()
.map(Episode.fromJson)
.toList(),
);
}
}