370 lines
12 KiB
Dart
370 lines
12 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:hgdj/assets_tool/app_colors.dart';
|
||
import 'package:hgdj/hj_model/splash/ads_model.dart';
|
||
import 'package:hgdj/hj_model/video_model.dart';
|
||
import 'package:hgdj/tools_base/global_store/store.dart';
|
||
|
||
import 'acg/comic_chapters_model.dart';
|
||
import 'actress_info.dart';
|
||
import 'media_content.dart';
|
||
|
||
class CartoonMediaInfo {
|
||
// —— 基础信息 ——
|
||
String? id; //文档id
|
||
String? title; //标题
|
||
String? author; //作者
|
||
String? summary; //简介
|
||
String? mediaType; //媒体类型 "video":动漫,"image":漫画 "text":小说
|
||
int? mediaSubType; //子类型 ,暂时只有小说使用 0-默认文本小说 1-有声小说
|
||
int? kind; //种类(1、哩番,2、3D,3、同人动画,4、单行本,5、连载漫画,6、韩漫 )
|
||
int? status; //状态
|
||
VidStatus? mediaStatus; //媒体状态
|
||
String? lsjId; // 老司机媒体资源ID
|
||
|
||
// —— 封面 ——
|
||
String? horizontalCover; //横版封面
|
||
String? verticalCover; //竖版封面
|
||
|
||
// —— 集数 / 更新 ——
|
||
int? totalEpisode; //总集数
|
||
int? currentEpisode; //当前集数
|
||
int? freeEpisode; //免费集数
|
||
bool isCartoonFreeEpisode =
|
||
false; //当前播放集是否属于免费集(前 freeEpisode 集):运行时按当前集号计算,命中则不拦播、进度可全程拖
|
||
int? updateStatus; //更新状态 0 默认 1、更新中 2、已完结
|
||
String? updateTime; //文档更新时间
|
||
String? createdAt; //文档创建时间
|
||
|
||
// —— 价格 / 权限 ——
|
||
int? price; //价格(整部购买的类型 小说 cos 写真)
|
||
int? discountPrice; // 折扣价(后端字段,App 未使用)
|
||
int? contentsPrice; //所有子集的价格
|
||
int? permission; // 0:会员 1:金币购买 2:免费
|
||
bool? permissionIconHide; //售卖类型标识隐藏
|
||
|
||
// —— 专题 / 模块 ——
|
||
String? mId; //模块ID
|
||
String? moduleName; //模块名称
|
||
String? sId; //专题id
|
||
String? sectionName; //专题名称
|
||
int? sectionSort; //专题排序
|
||
int? sortCode; //排序
|
||
|
||
// —— 统计 ——
|
||
int? countBrowse; //浏览数
|
||
int? countCollect; //收藏数
|
||
int? countDisLike; //不喜欢数
|
||
int? countComment; //评论数
|
||
int? countLike; //喜欢数
|
||
int? countPurchases; //购买数
|
||
int? countView; //展现数
|
||
bool? hasFollow; //是否关注
|
||
|
||
// —— 标签 / 演员 / 内容 ——
|
||
List<TagsBean>? tagDetails; //标签对象
|
||
List<ActressInfo>? allActress; // 演员列表
|
||
ActressInfo? actress; // 主演员
|
||
List<MediaContent>? contents; // 子集内容列表
|
||
AdsInfoModel? randomAdsInfo; // 随机广告
|
||
|
||
// —— 其他后端字段 ——
|
||
int? direction; // 方向(横/竖)
|
||
int? freeTime; // 免费试看时长
|
||
bool? isDelete; // 是否已删除
|
||
int? choiceSort; // 后端字段,App 未使用
|
||
int? countPurchasesRate; // 后端字段,App 未使用
|
||
String? updatedAct; // 后端字段,App 未使用
|
||
|
||
// —— 本地 / UI 字段(非后端返回) ——
|
||
List<ComicChapterInfo>? episodeList; // 通过接口获取,外部赋值(改版了,不是同一个接口返回)
|
||
int? episodeCurPage; // 当前页码
|
||
int episodePageSize = 40; // 每页集数
|
||
int isUpSort = 0; //0-正序 1-倒序
|
||
bool haxNextEpisode = true; // 是否还有下一页
|
||
int? episodeNumber; //本地添加字段。用于判断,跳转到播放详情的index
|
||
bool isSelected = false; // 是否选中
|
||
String? heroTag; //本地字段,用于传递hero动画tag 随机数
|
||
|
||
String? get coverH =>
|
||
horizontalCover?.isNotEmpty == true ? horizontalCover : verticalCover;
|
||
|
||
String? get coverV =>
|
||
verticalCover?.isNotEmpty == true ? verticalCover : horizontalCover;
|
||
|
||
String get unit => mediaType == 'image' ? '话' : '章';
|
||
//更新状态
|
||
String get updateDesc => updateStatus == 1 ? '连载中' : '已完结';
|
||
|
||
String get tagIds => tagDetails?.map((e) => e.id).toList().join(',') ?? '';
|
||
String get tagNames =>
|
||
tagDetails?.map((e) => e.name).toList().join(',') ?? '';
|
||
|
||
//更新状态
|
||
String get getDetailUpdateString {
|
||
if (updateStatus == 2 || updateStatus == 0) {
|
||
return '已完结';
|
||
} else {
|
||
return '连载中';
|
||
}
|
||
}
|
||
|
||
Color get getDetailUpdateColor {
|
||
if (updateStatus == 2 || updateStatus == 0) {
|
||
return Color(0xff989898);
|
||
} else {
|
||
return AppColors.actionRed;
|
||
}
|
||
}
|
||
|
||
//是否是有声小说
|
||
bool get isAudiobooks => mediaType == 'text' && mediaSubType == 1;
|
||
|
||
//集数状态描述
|
||
String get episodeNumberStatus {
|
||
if (updateStatus == 1) {
|
||
if (currentEpisode == 0) {
|
||
return '共$totalEpisode$unit';
|
||
} else {
|
||
return '更新$currentEpisode$unit';
|
||
}
|
||
} else {
|
||
return '共$totalEpisode$unit';
|
||
}
|
||
}
|
||
|
||
//评论类型,传参数类型
|
||
String get commentType => 'cartoon';
|
||
|
||
/// 该集是否落在前 N 集免费区间内。
|
||
/// 集号缺失兜底为 1(与项目其他处 `episodeNumber ?? 1` 口径一致);服务端真给 0 或负数时判为非免费
|
||
bool isFreeEpisodeNumber(int? episodeNumber) {
|
||
final ep = episodeNumber ?? 1;
|
||
return ep >= 1 && (freeEpisode ?? 0) >= ep;
|
||
}
|
||
|
||
/// 转成播放器用的 [VideoModel],[episode] 为当前集
|
||
/// 顺带把 [isCartoonFreeEpisode] 按当前集号刷新一次(有副作用,别当纯转换用)
|
||
VideoModel toVideoModel(ComicChapterInfo? episode) {
|
||
final model = VideoModel()
|
||
..videoType = 1
|
||
..id = id
|
||
..totalEpisode = totalEpisode
|
||
..updateStatus = updateStatus
|
||
..mediaType = mediaType
|
||
..mediaInfo = this
|
||
..title = title
|
||
..tags = tagDetails
|
||
..cover = coverH
|
||
..likeCount = countCollect // 视频likecount是收藏数
|
||
..freeTime = freeTime ?? 0
|
||
..collectCount = countCollect
|
||
..commentCount = countComment
|
||
..playCount = countBrowse
|
||
..freeArea = permission == 2
|
||
..coins = price
|
||
..originCoins = price
|
||
..vidStatus = (VidStatus()
|
||
..hasPaid = mediaStatus?.hasPaid == true
|
||
..hasCollected = mediaStatus?.hasCollected
|
||
..hasLiked = mediaStatus?.hasLiked
|
||
..hasDisliked = mediaStatus?.hasDisliked);
|
||
|
||
// 动漫免费集:当前集号在前 freeEpisode 集内 → 播放不拦、进度可全程拖(与 video_logic 免费章节判定同一口径)
|
||
isCartoonFreeEpisode = isFreeEpisodeNumber(episode?.episodeNumber);
|
||
|
||
final list = episodeList ?? [];
|
||
if (list.isNotEmpty) {
|
||
//在列表里找不到当前集就退回第一集,别让播放信息整块空掉
|
||
final index = list.indexWhere((e) => e.id == episode?.id);
|
||
final content = list[index < 0 ? 0 : index].mediaContent;
|
||
model
|
||
..subid = content?.id
|
||
..name = content?.name
|
||
..sourceURL = content?.videoUrl
|
||
..playTime = content?.playTime;
|
||
}
|
||
return model;
|
||
}
|
||
|
||
//acg子集角标显示逻辑,0:会员 1:金币购买 2:免费。为 false(无任何权限)时才展示角标
|
||
bool get hasPermission {
|
||
return (mediaStatus?.hasPaid == true && permission == 1) ||
|
||
permission == 2 ||
|
||
(permission == 0 && globalStore.isVIP) ||
|
||
globalStore.isSuperUp;
|
||
}
|
||
|
||
CartoonMediaInfo(
|
||
{this.contents,
|
||
this.choiceSort,
|
||
this.countBrowse,
|
||
this.countCollect,
|
||
this.countComment,
|
||
this.countLike,
|
||
this.countPurchases,
|
||
this.countPurchasesRate,
|
||
this.countView,
|
||
this.createdAt,
|
||
this.direction,
|
||
this.freeTime,
|
||
this.horizontalCover,
|
||
this.id,
|
||
this.isDelete,
|
||
this.kind,
|
||
this.mId,
|
||
this.mediaType,
|
||
this.moduleName,
|
||
this.permission,
|
||
this.permissionIconHide,
|
||
this.price,
|
||
this.sId,
|
||
this.discountPrice,
|
||
this.sectionName,
|
||
this.sectionSort,
|
||
this.sortCode,
|
||
this.status,
|
||
this.summary,
|
||
this.tagDetails,
|
||
this.title,
|
||
this.totalEpisode,
|
||
this.currentEpisode,
|
||
this.updateStatus,
|
||
this.updateTime,
|
||
this.updatedAct,
|
||
this.verticalCover,
|
||
this.author,
|
||
this.freeEpisode,
|
||
this.contentsPrice,
|
||
this.mediaSubType,
|
||
this.actress});
|
||
|
||
CartoonMediaInfo.fromJson(dynamic json) {
|
||
freeEpisode = json['freeEpisode'];
|
||
mediaSubType = json['mediaSubType'];
|
||
author = json['author'];
|
||
|
||
choiceSort = json['choiceSort'];
|
||
totalEpisode = json['totalEpisode'];
|
||
currentEpisode = json['currentEpisode'];
|
||
countBrowse = json['countBrowse'];
|
||
countCollect = json['countCollect'];
|
||
countComment = json['countComment'];
|
||
countLike = json['countLike'];
|
||
countDisLike = json['countDisLike'];
|
||
countPurchases = json['countPurchases'];
|
||
countPurchasesRate = json['countPurchasesRate'];
|
||
discountPrice = json['discountPrice'];
|
||
countView = json['countView'];
|
||
createdAt = json['createdAt'];
|
||
direction = json['direction'];
|
||
freeTime = json['freeTime'];
|
||
horizontalCover = json['horizontalCover'];
|
||
id = json['id'];
|
||
isDelete = json['isDelete'];
|
||
kind = json['kind'];
|
||
mId = json['mId'];
|
||
mediaType = json['mediaType'];
|
||
moduleName = json['moduleName'];
|
||
|
||
permission = json['permission'];
|
||
permissionIconHide = json['permissionIconHide'];
|
||
price = json['price'];
|
||
sId = json['sId'];
|
||
sectionName = json['sectionName'];
|
||
sectionSort = json['sectionSort'];
|
||
|
||
sortCode = json['sortCode'];
|
||
status = json['status'];
|
||
summary = json['summary'];
|
||
lsjId = json['lsjId'];
|
||
actress =
|
||
json["actress"] == null ? null : ActressInfo.fromJson(json["actress"]);
|
||
allActress = json["actresses"] == null
|
||
? []
|
||
: List<ActressInfo>.from(
|
||
json["actresses"]!.map((x) => ActressInfo.fromJson(x)));
|
||
hasFollow = json['hasFollow'];
|
||
if (json['tagDetails'] != null) {
|
||
tagDetails = [];
|
||
json['tagDetails'].forEach((v) {
|
||
tagDetails?.add(TagsBean.fromMap(v));
|
||
});
|
||
}
|
||
if (json['contents'] != null) {
|
||
contents = [];
|
||
json['contents'].forEach((v) {
|
||
contents?.add(MediaContent.fromJson(v));
|
||
});
|
||
}
|
||
|
||
if (json['title'] == null) {
|
||
title = json['name'];
|
||
} else {
|
||
title = json['title'];
|
||
}
|
||
updateStatus = json['updateStatus'];
|
||
updateTime = json['updateTime'];
|
||
updatedAct = json['updatedAct'];
|
||
verticalCover = json['verticalCover'];
|
||
mediaStatus = VidStatus.fromMap(json['mediaStatus']);
|
||
contentsPrice = json['contentsPrice'];
|
||
}
|
||
|
||
///videoModel是否随机广告
|
||
bool isRandomAd() {
|
||
return randomAdsInfo != null;
|
||
}
|
||
|
||
Map<String, dynamic> toJson() {
|
||
final map = <String, dynamic>{};
|
||
map['mediaSubType'] = mediaSubType;
|
||
map['choiceSort'] = choiceSort;
|
||
map['countBrowse'] = countBrowse;
|
||
map['countCollect'] = countCollect;
|
||
map['countComment'] = countComment;
|
||
map['countLike'] = countLike;
|
||
map['countDisLike'] = countDisLike;
|
||
map['countPurchases'] = countPurchases;
|
||
map['countPurchasesRate'] = countPurchasesRate;
|
||
map['countView'] = countView;
|
||
map['createdAt'] = createdAt;
|
||
map['direction'] = direction;
|
||
map['freeTime'] = freeTime;
|
||
map['horizontalCover'] = horizontalCover;
|
||
map['id'] = id;
|
||
map['isDelete'] = isDelete;
|
||
map['kind'] = kind;
|
||
map['mId'] = mId;
|
||
map['mediaType'] = mediaType;
|
||
map['moduleName'] = moduleName;
|
||
|
||
map['permission'] = permission;
|
||
map['permissionIconHide'] = permissionIconHide;
|
||
map['price'] = price;
|
||
map['sId'] = sId;
|
||
map['sectionName'] = sectionName;
|
||
map['sectionSort'] = sectionSort;
|
||
|
||
map['sortCode'] = sortCode;
|
||
map['status'] = status;
|
||
map['summary'] = summary;
|
||
map['lsjId'] = lsjId;
|
||
if (tagDetails != null) {
|
||
map['tagDetails'] = tagDetails?.map((v) => v.toJson()).toList();
|
||
}
|
||
if (contents != null) {
|
||
map['contents'] = contents?.map((v) => v.toJson()).toList();
|
||
}
|
||
map['hasFollow'] = hasFollow;
|
||
map['title'] = title;
|
||
map['totalEpisode'] = totalEpisode;
|
||
map['currentEpisode'] = currentEpisode;
|
||
map['updateTime'] = updateTime;
|
||
map['updateStatus'] = updateStatus;
|
||
map['updatedAct'] = updatedAct;
|
||
map['verticalCover'] = verticalCover;
|
||
map['mediaStatus'] = mediaStatus;
|
||
return map;
|
||
}
|
||
}
|