Files
huangguo_android/lib/hj_page/cartoon/cartoon_detail_logic.dart
T
2026-09-15 15:44:13 +07:00

110 lines
3.5 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hgdj/hj_utils/const.dart';
import 'package:hgdj/tools_base/event_bus/events.dart';
import 'package:hgdj/tools_base/widget/scroll_positioned_list/src/scrollable_positioned_list.dart';
import '../../../hj_model/acg/comic_chapters_model.dart';
import '../../../hj_model/cartoon_media_info.dart';
import '../../../hj_utils/api_service/acg_service.dart';
import '../../hj_utils/history_util.dart';
import '../../tools_base/event_bus/event_bus_util.dart';
import 'cartoon_read_page.dart';
import 'widget/acg_source_manager.dart';
import 'widget/cartoon_subset_alert.dart';
class CartoonDetailLogic extends GetxController
with GetTickerProviderStateMixin {
String? id;
CartoonMediaInfo? mediaInfo;
bool showHeader = true;
double showOffset = 245;
bool get isCartoonType => manager.mediaInfo?.mediaType == 'image'; //是否是动画
// 推荐 tab 固定 3 个(漫画/视频/动漫),顺序由页面按当前内容类型动态排
late TabController tabCtr = TabController(length: 3, vsync: this);
late ScrollController scrollCtr = ScrollController()
..addListener(() {
//滚过阈值切换顶部沉浸 header,状态变了才刷新
final show = scrollCtr.offset <= showOffset;
if (show != showHeader) {
showHeader = show;
update(['header']);
}
});
final ItemScrollController itemSCtrl = ItemScrollController();
late ACGSourceManager manager;
late StreamSubscription subscription;
CartoonDetailLogic({this.id})
: manager = ACGSourceManager(id ?? ''); //初始化,加载子集
@override
void onReady() async {
super.onReady();
// subscription 是 late,必须在任何 await 前初始化,
// 否则详情加载途中退出会让 onClose 的 cancel() 打到未初始化字段而崩
subscription = eventBus.on<ACGMenuChanged>((event) {
//列表未 attach(未 build/布局完)时 jumpTo 内部会 ! 取空崩溃,加保护
if (itemSCtrl.isAttached) {
itemSCtrl.jumpTo(index: event.index ?? 0);
}
});
// 先拿详情(含 freeEpisode),再拉子集,才能正确标记前 N 集免费
await loadData();
manager.fetchAllEpisodes();
}
@override
void onClose() {
subscription.cancel();
eventBus.off(subscription);
tabCtr.dispose(); //修复泄漏
scrollCtr.dispose(); //修复泄漏
// manager 由页面的 ChangeNotifierProvider(create:) 在卸载时 dispose,本类不再重复释放
super.onClose();
}
//获取媒体详情
Future loadData() async {
mediaInfo = await ACGService.getMediaInfo(id ?? '');
if (mediaInfo != null) {
HistoryUtil.insert(mediaInfo!, MediaStyle.Comics);
manager.mediaInfo = mediaInfo;
showOffset = mediaInfo?.mediaType == 'text' ? 300 : 320;
} else {
mediaInfo = CartoonMediaInfo();
}
update();
}
//切换集数
changeEpisode(int episode, bool jump) async {
manager.changeEpisodesIndex(episode, jump: jump);
play(); //播放
}
play() async {
//判断权限
ComicChapterInfo? info =
await manager.getEpisodeHasPermisson(manager.index);
if (info == null) return;
Get.to(() => CartoonReadPage(manager: manager..index = manager.index));
}
//集数弹窗
onMenuAction() async {
int episode = await Get.bottomSheet(
CartoonSubSetAlert(sourceManager: manager),
barrierColor: Colors.black.withValues(alpha: .2),
);
if (episode > -1) {
changeEpisode(episode, true);
}
}
}