import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hgdj/hj_model/drama/drama_models.dart'; import 'package:hgdj/hj_model/video_model.dart'; import 'package:hgdj/tools_base/cache/history/drama_resume_store.dart'; import 'package:hgdj/hj_utils/api_service/drama_service.dart'; import 'package:hgdj/tools_base/debug_log.dart'; import 'package:uuid/uuid.dart'; /// AI短剧信息流:一条 = 一部剧的第 1 集,竖划换下一部剧。 /// 排序、去重、已看沉底全在服务端,**没有页码**——每次请求就是下一批,客户端不得二次排序, /// 也不做二次去重(服务端目前会重发同一部剧,去重就意味着列表不增长、用户直接划不动) class DramaFeedLogic extends GetxController { // GetBuilder 局部刷新 id:当前页变化时只刷信息流 static const idFeed = 'feed'; // ===== 外部传入 ===== final TabController? superTabCtr; // 外层频道 tab,用于切到本 tab 时补加载 final int? tabIndex; DramaFeedLogic({this.superTabCtr, this.tabIndex}); // ===== 状态 ===== bool isFirstLoaded = false; // 首屏是否加载完成(false 时显示 loading) bool isLoading = false; // 防并发翻页 bool hasNext = true; /// 本批的幂等键:网络重试沿用,拿到结果才作废 String? _requestId; // ===== 数据 ===== List? list; // ===== 交互态 ===== int pageIndex = 0; // 当前显示第几条 // ===== Controller ===== late PageController pageCtr; final ValueNotifier isScrolling = ValueNotifier(false); // 上下滑动切剧时隐藏进度条 @override void onInit() { super.onInit(); pageCtr = PageController(initialPage: pageIndex); superTabCtr?.addListener(_onTabChanged); //续播位置是本地记的,进来就把表读上来。不用 await:读的是本地 sqflite,比首批网络请求快得多, //播放器起播时(要等 /media_content/info 回来)必然已就绪 dramaResume.load(); loadData(); } @override void onClose() { superTabCtr?.removeListener(_onTabChanged); pageCtr.dispose(); isScrolling.dispose(); super.onClose(); } // 切到本 tab 且还没数据就补一次 void _onTabChanged() { if (superTabCtr?.index == tabIndex && list?.isEmpty == true) loadData(); } /// [isRefresh] 下拉刷新时清空重来,否则往后追加 Future loadData({bool isRefresh = true}) async { if (isLoading) return; if (!isRefresh && !hasNext) return; isLoading = true; try { final resp = await DramaService.fetchFeed( size: 20, requestId: _requestId ??= const Uuid().v4()); if (resp != null) _requestId = null; // 成功才作废;失败重试沿用同一个 id,避免服务端当成两批 //拿到什么收什么,不按剧 id 去重:服务端反复下发同一部剧时,去重会让列表不增长, //用户停在最后一条划不动、onPageChanged 也不再触发,就彻底卡死了。 //宁可刷到重复的剧,也不能卡住——重复的 key 由页面用「剧 id + 下标」避开 final more = []; for (final item in resp?.list ?? const []) { final media = item.media; if (media == null) continue; // 缺 media 的脏数据,别在信息流里留个空位 more.add(media.toVideoModel(item.content)); } hasNext = resp?.hasNext ?? false; list = isRefresh ? more : [...?list, ...more]; } catch (e) { list ??= []; debugLog('短剧信息流获取失败:$e'); } isLoading = false; isFirstLoaded = true; update(); } void onPageChanged(int index) { if (pageIndex != index) { pageIndex = index; update([idFeed]); // 只刷信息流,各 item 重算 isCurrentPage } // 快到底了先把下一批拉上,别等滑到最后一条才请求 if (hasNext && (list?.length ?? 0) - index <= 6) loadData(isRefresh: false); } }