初始化

This commit is contained in:
谢宇宁
2026-09-15 15:44:13 +07:00
commit a23ba685e9
1065 changed files with 101122 additions and 0 deletions
@@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:hgdj/assets_tool/images.dart';
import 'package:hgdj/hj_model/video_model.dart';
import 'package:hgdj/hj_utils/const.dart';
import 'package:hgdj/hj_utils/screen.dart';
import 'package:hgdj/tools_base/video_download/media_download_manager.dart';
/// 视频下载按钮,短视频 / 长视频 / 短剧 / 动漫共用。
/// 只管画状态和转发点击;权限、扣次、落记录、进度回调全在 [MediaDownloadManager]
class DownloadButton extends StatefulWidget {
final VideoModel? video;
/// true 竖排(短视频那套图标),false 横排(长视频),只影响外观
final bool isShort;
/// 缓存记录落哪个桶。不传时按 [isShort] 推断(短视频 / 影视 / 动漫);
/// 短剧在操作台里排版同短视频,但要单独归类,所以显式传 [MediaStyle.Drama]
final MediaStyle? style;
const DownloadButton(
{super.key, this.video, this.isShort = true, this.style});
@override
State<DownloadButton> createState() => _DownloadButtonState();
}
class _DownloadButtonState extends State<DownloadButton> {
late DownloadTask _task;
/// 免费下载一套图标,短视频/长视频各一套
String get _icon => (widget.video?.isFreeDownload == true
? "download_free.png"
: widget.isShort
? "download_short.png"
: "download.png")
.videoPath;
/// 保存到缓存库时的媒体类型
MediaStyle get _mediaStyle {
final style = widget.style;
if (style != null) return style;
if (widget.isShort) return MediaStyle.ShortVideo;
return widget.video?.videoType == 1 ? MediaStyle.Cartoon : MediaStyle.Video;
}
@override
void initState() {
super.initState();
_task = MediaDownloadManager.instance
.attach(video: widget.video, style: _mediaStyle, onChanged: _refresh);
}
@override
void didUpdateWidget(covariant DownloadButton oldWidget) {
super.didUpdateWidget(oldWidget);
//列表/PageView 复用 State 时会换 model,会话得跟着换:不换的话按钮画的是上一条的状态,
//点下载下的也是上一条。同一个对象(父级只是重建)就别白折腾
if (identical(oldWidget.video, widget.video)) return;
_task.detach();
_task = MediaDownloadManager.instance
.attach(video: widget.video, style: _mediaStyle, onChanged: _refresh);
}
@override
void dispose() {
_task.detach();
super.dispose();
}
/// 本按钮在短视频列表里随滑动大量创建/销毁,下载回调由单例持有、dispose 后仍可能被调到,统一判 mounted
void _refresh() {
if (mounted) setState(() {});
}
@override
Widget build(BuildContext context) {
final isShort = widget.isShort;
final icon = SizedBox(
width: isShort ? 30 : 24,
height: isShort ? 30 : 24,
child: Image.asset(_icon),
);
final label = Text(
_task.state.desc,
style: isShort
? const TextStyle(
color: Color(0xffdcdcdc),
fontSize: 12,
fontWeight: FontWeight.w500)
: const TextStyle(color: Color(0xff989898), fontSize: 12),
);
return InkWell(
enableFeedback: false,
onTap: _task.start,
child: isShort
? Column(mainAxisSize: MainAxisSize.min, children: [icon, label])
: Row(
mainAxisSize: MainAxisSize.min,
children: [icon, 2.sizeBoxW, label]),
);
}
}