import 'package:collection/collection.dart'; import 'package:hgdj/hj_utils/const.dart'; //亚模块模型 class ModuleData { String? id; String? moduleName; //1首页(原首页视频) 2社区 3暗网 4动漫 5漫画 6小说 7黄油 8图集 9短视频 10私密圈 11AI广场 12短剧 int? type; //1 模块普通海角系样式(HJShowType) 2 全专题组合样式(AllSectionShowType) int? showType; bool? pureVersion; //true:广告纯净模式 String? defaultTagId; //社区默认选中 HaiJiaoStyle? haiJiaoStyle; ModuleData({this.moduleName, this.type, this.id, this.showType}); ModuleData.fromJson(Map? json) { json ??= {}; id = json['id']; moduleName = json['moduleName']; type = json['type']; showType = json['showType']; pureVersion = json['pureVersion']; defaultTagId = json['defaultTagId']; haiJiaoStyle = HaiJiaoStyle.fromJson(json['haiJiaoStyle']); } //只给 ModuleSortManager 存本地排序用,读回来只按 id 跟后端最新数据配对,故不存 haiJiaoStyle 等内容字段 Map toJson() { return { "id": id, "moduleName": moduleName, "type": type, "showType": showType, 'defaultTagId': defaultTagId, }; } //动漫/漫画/小说 bool get isACG => type == 4 || type == 5 || type == 6; /// 展示用的排序项:top=true 的置顶,最多 4 个。 /// 标题、sort 值、随机刷新配置一律从这份派生——分头各排一次,遇到同名/同值 remove 会删错元素,两边就对不上了。 /// haiJiaoStyle 解析完就不再变,算一次存起来,别每个 getter 各构造一遍 late final List _sortedRules = () { final rules = [...?haiJiaoStyle?.sortRules]; final topIndex = rules.indexWhere((e) => e.top == true); if (topIndex > 0) rules.insert(0, rules.removeAt(topIndex)); return rules.length > 4 ? rules.sublist(0, 4) : rules; }(); /// 排序 tab(标题 + sort 值),为空返回 null 让调用方退回默认值。 /// 标题和 sort 值必须一起产出:拆成两个并行数组时,后端只下发其中一个就会静默错位 List>? get sortTabs => _sortedRules.isEmpty ? null : _sortedRules.map((e) => SortTab(e.name ?? '', e.val ?? -1)).toList(); /// 按 sort 值取对应的排序规则(用于判断该排序项是否走随机刷新接口) SortRuleModel? sortRuleOf(int? val) => _sortedRules.firstWhereOrNull((e) => e.val == val); } class HaiJiaoStyle { int? defaultShow; //默认展示 0-一排两个 1-一排一个 int? sectionStyle; //专题展示样式 0-不展示 1-十六岁专题 2-女优专题 3-网黄专题 4-普通专题 int? showChosenVideo; //0-不展示精选视频 1-展示精选视频 int? sortShow; //排序规则展示样式 0-不展示 1-展示 List? sortRules; //排序规则 HaiJiaoStyle.fromJson(Map? json) { json ??= {}; defaultShow = json['defaultShow']; sectionStyle = json['sectionStyle']; showChosenVideo = json['showChosenVideo']; sortShow = json['sortShow']; final rules = json['sortRules']; if (rules is List) sortRules = rules.map((e) => SortRuleModel.fromJson(e)).toList(); } } class SortRuleModel { int? val; bool? top; //是否置顶 String? name; //刷新模式 DEFAULT / RANDOM_TOP_N,判断随机刷新只认这个字段,不许匹配 name 或硬编码 val String? refreshMode; SortRuleModel.fromJson(Map? json) { json ??= {}; val = json['val']; top = json['top']; name = json['name']; refreshMode = json['refreshMode']; } bool get isRandomRefresh => refreshMode == 'RANDOM_TOP_N'; } class HomePlateModel { //解析一律走 _modules,字段缺失也退化成空列表,所以都是非空的,调用方不用判空 List homePage = []; //首页-视频 List deepWeb = []; //暗网 List community = []; //社区 List novel = []; //小说 List pics = []; //图集:后端原始模块,展示要用 picsUi List game = []; //黄游:后端原始模块,展示要用 gameUi List dramaPage = []; //短剧专题(与 update-markers.modules 按 id 对齐) //图集:固定注入「热门推荐」(type -100 对应 PIC 数据源) 再接后端模块 List get picsUi => [ ModuleData(moduleName: '热门推荐', type: -100, showType: 1), ...pics, ]; //黄游:固定注入「热门推荐」(type -101 对应 SEED_LINK 数据源) 再接后端模块,showType 2 走列表样式 List get gameUi => [ ModuleData(moduleName: '热门推荐', type: -101, showType: 2), ...game, ]; HomePlateModel.fromJson(Map? json) { json ??= {}; homePage = _modules(json['homePage']); deepWeb = _modules(json['deepWeb']); community = _modules(json['community']); novel = _modules(json['novel']); pics = _modules(json['pics']); game = _modules(json['game']); dramaPage = _modules(json['dramaPage']); } //字段缺失或类型不对(后端偶发下发非数组)都退化成空列表,别让首页解析整个抛掉 static List _modules(dynamic list) => (list is List ? list : const []) .map((e) => ModuleData.fromJson(e)) .toList(); }