flutter/lib/pages/video/module/recommend.dart
2025-08-21 17:50:34 +08:00

1013 lines
45 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// 精选推荐模块
library;
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/controller/chat_controller.dart';
import 'package:loopin/IM/im_core.dart';
import 'package:loopin/IM/im_message.dart';
import 'package:loopin/api/video_api.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/summary_type.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/utils/wxsdk.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:media_kit_video/media_kit_video_controls/src/controls/extensions/duration.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
import '../../../behavior/custom_scroll_behavior.dart';
import '../../../controller/video_module_controller.dart';
import '../../../router/fade_route.dart';
import '../components/popup_reply.dart';
class RecommendModule extends StatefulWidget {
const RecommendModule({super.key});
static Player? _player;
static void setPlayer(Player player) {
_player = player;
}
static void pauseVideo() {
_player?.pause();
}
static void playVideo() {
_player?.play();
}
@override
State<RecommendModule> createState() => _RecommendModuleState();
}
class _RecommendModuleState extends State<RecommendModule> {
VideoModuleController videoModuleController = Get.put(VideoModuleController());
final ChatController chatController = Get.find<ChatController>();
// class _RecommendModuleState extends State<RecommendModule> with AutomaticKeepAliveClientMixin {
// @override
// bool get wantKeepAlive => true;
// VideoModuleController videoModuleController = Get.find<VideoModuleController>();
// 分页内容
int page = 1;
final int pageSize = 10;
bool isLoadingMore = false;
// 页面controller
late PageController pageController = PageController(
initialPage: videoModuleController.videoPlayIndex.value,
viewportFraction: 1.0,
);
// 播放器controller
late Player player = Player();
late VideoController videoController = VideoController(player);
final List<StreamSubscription> subscriptions = [];
// 进度条slider当前阈值
double sliderValue = 0.0;
bool sliderDraging = false;
late Duration position = Duration.zero; // 当前时长
late Duration duration = Duration.zero; // 总时长
// 视频数据
List videoList = [];
// 评论数据
List commentList = [
{'avatar': 'assets/images/avatar/img01.jpg', 'name': 'Alice', 'desc': '用汗水浇灌希望,让努力铸就辉煌,你付出的每一刻,都是在靠近成功的彼岸。'},
{'avatar': 'assets/images/avatar/img02.jpg', 'name': '悟空', 'desc': '黑暗遮不住破晓的曙光,困境困不住奋进的脚步,勇往直前,你定能冲破阴霾。'},
{'avatar': 'assets/images/avatar/img03.jpg', 'name': '木棉花', 'desc': '每一次跌倒都是为了下一次更有力地跃起,别放弃~'},
{'avatar': 'assets/images/avatar/img04.jpg', 'name': '狗仔', 'desc': '人生没有白走的路,每一步都算数,那些辛苦的过往,会在未来化作最美的勋章。'},
{'avatar': 'assets/images/avatar/img05.jpg', 'name': '向日葵', 'desc': '以梦为马,不负韶华,握紧手中的笔,书写属于自己的热血传奇,让青春绽放光芒。'},
{'avatar': 'assets/images/avatar/img06.jpg', 'name': '健身女神', 'desc': '哪怕身处谷底,只要抬头仰望,便能看见漫天繁星,心怀希望,就能找到出路,奔赴美好。'},
];
// 分享列表
List shareList = [
{'icon': 'assets/images/share-wx.png', 'label': '好友'},
{'icon': 'assets/images/share-wx.png', 'label': '微信'},
{'icon': 'assets/images/share-pyq.png', 'label': '朋友圈'},
{'icon': 'assets/images/share-link.png', 'label': '复制链接'},
{'icon': 'assets/images/share-download.png', 'label': '下载'},
{'icon': 'assets/images/share-download.png', 'label': '下载'},
{'icon': 'assets/images/share-download.png', 'label': '下载'},
{'icon': 'assets/images/share-download.png', 'label': '下载'},
{'icon': 'assets/images/share-download.png', 'label': '下载下载下载下载下载下载下载下载下载下载下载下载'},
{'icon': 'assets/images/share-download.png', 'label': '下载下载下载下载下载下载下载下载下载下载下载下载'},
];
@override
void initState() {
super.initState();
videoModuleController.needRefresh.listen((need) {
if (need) {
reInit();
videoModuleController.clearNeedRefresh();
}
});
RecommendModule.setPlayer(player);
// 获取视频数据
fetchVideoList();
}
@override
void setState(VoidCallback fn) {
if (mounted) {
super.setState(fn);
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (subscriptions.isEmpty) {
subscriptions.addAll(
[
// 监听视频时长
player.stream.duration.listen((event) {
setState(() {
duration = event;
});
}),
// 监听视频播放进度
player.stream.position.listen((event) {
setState(() {
position = event;
if (position > Duration.zero && !sliderDraging) {
// 设置视频播放位置
sliderValue = (position.inMilliseconds / duration.inMilliseconds).clamp(0.0, 1.0);
}
});
}),
],
);
}
}
@override
void dispose() {
player.dispose();
pageController.dispose();
for (final subscription in subscriptions) {
subscription.cancel();
}
super.dispose();
}
void reInit() async {
await player.stop();
// 重置状态
page = 1;
isLoadingMore = false;
videoList.clear();
videoModuleController.updateVideoPlayIndex(0);
sliderValue = 0.0;
sliderDraging = false;
position = Duration.zero;
duration = Duration.zero;
pageController.jumpToPage(0);
// 拉新数据
fetchVideoList();
}
Future<void> fetchVideoList() async {
if (isLoadingMore) return;
isLoadingMore = true;
try {
final res = await Http.post(VideoApi.vlogList, data: {
'current': page,
'size': pageSize,
});
final data = res['data'];
logger.d('关注用户的视频列表:$data');
if (data == null || (data is List && data.isEmpty)) {
// MyDialog.toast('没有更多了', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
return;
}
if (data['records'] is List) {
List videos = data['records'];
for (var item in videos) {
// print("喜欢:${item['likeCounts']}");
// print("评论:${item['commentsCounts']}");
// logger.i(item);
item['expanded'] = false;
}
setState(() {
if (page == 1) {
// 初始化
videoList = videos;
} else {
videoList.addAll(videos);
}
});
// 处理完成后
if (videos.isNotEmpty) {
page++;
}
logger.i('获取新的视频数据了');
// 初始化播放器
player.open(
Media(
videoList[videoModuleController.videoPlayIndex.value]['url'],
),
play: false);
player.setPlaylistMode(PlaylistMode.loop); // 循环播放;
// 第一次加载后播放第一个视频
if (page == 2 && videoModuleController.videoTabIndex.value == 2 && Get.currentRoute == '/' && videoModuleController.layoutPageCurrent.value == 0) {
player.play(); // 播放第一个
} else {
logger.i('没播放视频');
}
}
} catch (e) {
logger.i('获取视频失败: $e');
} finally {
isLoadingMore = false; // 加载完成,标记为 false
}
}
// 评论弹框
void handleComment(index) {
//获取评论数据
showModalBottomSheet(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(15.0))),
showDragHandle: false,
clipBehavior: Clip.antiAlias,
isScrollControlled: true, // 屏幕最大高度
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 3 / 4, // 自定义最大高度
),
context: context,
builder: (context) {
return Material(
color: Colors.white,
child: Column(
children: [
Container(
padding: EdgeInsets.fromLTRB(15.0, 10.0, 10.0, 5.0),
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Color(0xFFFAFAFA)))),
child: Column(
spacing: 10.0,
children: [
Row(
children: [
Expanded(
child: Text.rich(TextSpan(children: [
TextSpan(
text: '大家都在搜: ',
style: TextStyle(color: Colors.grey),
),
TextSpan(
text: '黑神话-悟空',
style: TextStyle(color: const Color(0xFF496D80)),
),
]))),
GestureDetector(
child: Container(
height: 22.0,
width: 22.0,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(100.0),
),
child: UnconstrainedBox(child: Icon(Icons.close, color: Colors.black45, size: 14.0))),
onTap: () {
Get.back();
},
),
],
),
Text(
'168条评论',
style: TextStyle(fontSize: 12.0, fontWeight: FontWeight.w600),
)
],
),
),
Expanded(
child: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: ListView.builder(
physics: BouncingScrollPhysics(),
shrinkWrap: true,
itemCount: commentList.length,
itemBuilder: (context, index) {
return ListTile(
isThreeLine: true,
leading: ClipRRect(
borderRadius: BorderRadius.circular(50.0),
child: Image.asset(
'${commentList[index]['avatar']}',
width: 30.0,
fit: BoxFit.contain,
),
),
title: Row(
children: [
Expanded(
child: Text(
'${commentList[index]['name']}',
style: TextStyle(
color: Colors.grey,
fontSize: 12.0,
),
),
),
Row(
children: [
Icon(
Icons.favorite_border_outlined,
color: Colors.black54,
size: 16.0,
),
Text(
'99',
style: TextStyle(color: Colors.black54, fontSize: 12.0),
),
],
),
SizedBox(
width: 20.0,
),
Row(
children: [
Icon(
Icons.heart_broken_outlined,
color: Colors.black54,
size: 16.0,
),
],
),
],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.symmetric(vertical: 5.0),
child: Text(
'${commentList[index]['desc']}',
style: TextStyle(
fontSize: 14.0,
),
),
),
Row(
children: [
Container(
margin: EdgeInsets.only(right: 15.0),
padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(20.0),
),
child: Row(children: [
Text(
'12回复',
style: TextStyle(fontSize: 12.0),
),
Icon(
Icons.arrow_forward_ios,
size: 10.0,
)
]),
),
Text(
'01-15 · 浙江',
style: TextStyle(color: Colors.grey, fontSize: 12.0),
),
],
),
],
),
);
},
),
),
),
GestureDetector(
child: Container(
margin: EdgeInsets.all(10.0),
height: 40.0,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(30.0),
),
child: Row(
children: [
SizedBox(
width: 15.0,
),
Icon(
Icons.edit_note,
color: Colors.black54,
size: 16.0,
),
SizedBox(
width: 5.0,
),
Text(
'说点什么...',
style: TextStyle(color: Colors.black54, fontSize: 14.0),
),
],
),
),
onTap: () {
navigator?.push(FadeRoute(child: PopupReply(
onChanged: (value) {
debugPrint('评论内容: $value');
},
)));
},
),
],
),
);
},
);
}
// 分享弹框
void handleShare(index) {
if (chatController.chatList.isNotEmpty) {
chatController.getConversationList();
}
showModalBottomSheet(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(15.0)),
),
clipBehavior: Clip.antiAlias,
context: context,
isScrollControlled: true,
builder: (context) {
return Material(
color: Colors.white,
child: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 分享列表
SizedBox(
height: 110,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: shareList.length,
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 20.0),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => handleShareClick(index),
child: Container(
width: 64,
margin: EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset('${shareList[index]['icon']}', width: 48.0),
SizedBox(height: 5),
Text(
'${shareList[index]['label']}',
style: TextStyle(fontSize: 12.0),
overflow: TextOverflow.ellipsis,
),
],
),
),
);
},
),
),
// 会话列表
Obx(() {
// 这里过滤掉有分组的会话
final filteredList = chatController.chatList.where((item) => item.conversation.conversationGroupList?.isEmpty == true).toList();
if (filteredList.isEmpty) return SizedBox.shrink();
return SizedBox(
height: 110,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: filteredList.length,
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 20.0),
itemBuilder: (context, index) {
return GestureDetector(
// 点击分享
onTap: () => handlCoverClick(filteredList[index].conversation),
child: Container(
width: 64,
margin: EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Image.asset('${chatController.chatList[index].faceUrl}', width: 48.0),
NetworkOrAssetImage(
imageUrl: filteredList[index].faceUrl,
width: 48.0,
height: 48.0,
),
SizedBox(height: 5),
Text(
'${filteredList[index].conversation.showName}',
style: TextStyle(fontSize: 12.0),
overflow: TextOverflow.ellipsis,
),
],
),
),
);
},
),
);
}),
// 取消按钮
SafeArea(
top: false,
child: InkWell(
onTap: () => Get.back(),
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: 50.0,
color: Colors.grey[50],
child: Text(
'取消',
style: TextStyle(color: Colors.black87),
),
),
),
),
],
),
),
);
},
);
}
void handleShareClick(int index) {
print("分享项 $index 被点击");
final description = videoList[videoModuleController.videoPlayIndex.value]['title'] ?? '获取title失败';
if (index == 1) {
// 好友
Wxsdk.shareToFriend(title: '快来看看这个视频', description: description, webpageUrl: 'https://baidu.com');
} else if (index == 2) {
// 朋友圈
Wxsdk.shareToTimeline(title: '快来看看这个视频', webpageUrl: 'https://baidu.com');
}
}
void handlCoverClick(V2TimConversation conv) async {
// 发送VideoMsg,获取当前视频信息
final userId = conv.userID;
final String url = videoList[videoModuleController.videoPlayIndex.value]['url'];
final img = videoList[videoModuleController.videoPlayIndex.value]['firstFrameImg'];
final width = videoList[videoModuleController.videoPlayIndex.value]['width'];
final height = videoList[videoModuleController.videoPlayIndex.value]['height'];
final makeJson = jsonEncode({
"width": width,
"height": height,
"imgUrl": img,
"videoUrl": url,
});
final res = await IMMessage().createCustomMessage(
data: makeJson,
);
if (res.success) {
final sendRes = await IMMessage().sendMessage(msg: res.data!.messageInfo!, toUserID: userId, cloudCustomData: SummaryType.shareVideo);
if (sendRes.success) {
MyToast().tip(
title: '分享成功',
position: 'center',
type: 'success',
);
Get.back();
} else {
logger.e(res.desc);
}
} else {
logger.e(res.desc);
}
}
@override
Widget build(BuildContext context) {
// super.build(context);
return Container(
color: Colors.black,
child: Column(
children: [
Expanded(
child: Stack(
children: [
/// 垂直滚动模块
PageView.builder(
// 自定义滚动行为(支持桌面端滑动、去掉滚动条槽)
scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
scrollDirection: Axis.vertical,
controller: pageController,
onPageChanged: (index) async {
// 更新当前播放视频索引
videoModuleController.updateVideoPlayIndex(index);
setState(() {
// 重置slider参数
sliderValue = 0.0;
sliderDraging = false;
position = Duration.zero;
duration = Duration.zero;
});
player.stop();
// await player.open(Media(videoList[index]['src']));
await player.open(Media(videoList[index]['url']));
// 如果滚动到列表末尾,且还有更多数据
if (index == videoList.length - 2 && !isLoadingMore) {
await fetchVideoList(); // 拉取更多
}
},
itemCount: videoList.length,
itemBuilder: (context, index) {
final videoWidth = videoList[index]['width'] ?? 1;
final videoHeight = videoList[index]['height'] ?? 1; // 防止除以0
final isHorizontal = videoWidth > videoHeight;
return Stack(
children: [
// 视频区域
Positioned(
top: 0,
left: 0,
right: 0,
bottom: 0,
child: GestureDetector(
child: Stack(
children: [
// 短视频插件
Visibility(
visible: videoModuleController.videoPlayIndex.value == index && position > Duration.zero,
child: Video(
controller: videoController,
fit: isHorizontal ? BoxFit.contain : BoxFit.cover,
// 无控制条
controls: NoVideoControls,
),
),
// 封面图播放后透明度渐变为0而不是直接隐藏
AnimatedOpacity(
opacity: videoModuleController.videoPlayIndex.value == index && position > Duration(milliseconds: 100) ? 0.0 : 1.0,
duration: Duration(milliseconds: 50),
child: Image.network(
videoList[index]['firstFrameImg'] ?? 'https://wuzhongjie.com.cn/download/logo.png',
fit: isHorizontal ? BoxFit.contain : BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
// 播放/暂停按钮
StreamBuilder(
stream: player.stream.playing,
builder: (context, playing) {
return Visibility(
visible: playing.data == false,
child: Center(
child: IconButton(
padding: EdgeInsets.zero,
onPressed: () {
player.playOrPause();
},
icon: Icon(
playing.data == true ? Icons.pause : Icons.play_arrow_rounded,
color: Colors.white60,
size: 80,
),
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.black.withAlpha(15))),
),
),
);
},
),
],
),
onTap: () {
player.playOrPause();
},
),
),
// 右侧操作栏
Positioned(
bottom: 100.0,
right: 6.0,
child: Column(
spacing: 15.0,
children: [
// 头像
Stack(
children: [
SizedBox(
height: 55.0,
width: 48.0,
child: GestureDetector(
onTap: () {
player.pause();
Get.toNamed('/vloger', arguments: videoList[videoModuleController.videoPlayIndex.value]);
},
child: UnconstrainedBox(
alignment: Alignment.topCenter,
child: Container(
height: 48.0,
width: 48.0,
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 2.0),
borderRadius: BorderRadius.circular(100.0),
),
child: ClipOval(
child: NetworkOrAssetImage(
imageUrl: videoList[index]['avatar'],
),
),
),
),
),
),
Positioned(
bottom: 0,
left: 15.0,
child: InkWell(
child: Container(
height: 18.0,
width: 18.0,
decoration: BoxDecoration(
color: videoList[index]['doIFollowVloger'] ? Colors.white : Color(0xFFFF5000),
borderRadius: BorderRadius.circular(100.0),
),
child: Icon(
videoList[index]['doIFollowVloger'] ? Icons.check : Icons.add,
color: videoList[index]['doIFollowVloger'] ? Color(0xFFFF5000) : Colors.white,
size: 14.0,
),
),
onTap: () {
setState(() {
videoList[index]['doIFollowVloger'] = !videoList[index]['doIFollowVloger'];
});
},
),
),
],
),
// 点赞
GestureDetector(
child: Column(
children: [
SvgPicture.asset(
'assets/images/svg/heart.svg',
colorFilter: ColorFilter.mode(videoList[index]['doILikeThisVlog'] ? Color(0xFFFF5000) : Colors.white, BlendMode.srcIn),
height: 40.0,
width: 40.0,
),
Text(
'${videoList[index]['likeCounts'] + (videoList[index]['doILikeThisVlog'] ? 1 : 0)}',
style: TextStyle(color: Colors.white, fontSize: 12.0),
),
],
),
onTap: () {
setState(() {
videoList[index]['doILikeThisVlog'] = !videoList[index]['doILikeThisVlog'];
});
},
),
// 评论
GestureDetector(
child: Column(
children: [
SvgPicture.asset(
'assets/images/svg/reply.svg',
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
height: 40.0,
width: 40.0,
),
Text(
'${videoList[index]['commentsCounts']}',
style: TextStyle(color: Colors.white, fontSize: 12.0),
),
],
),
onTap: () {
handleComment(index);
},
),
// Column(
// children: [
// SvgPicture.asset(
// 'assets/images/svg/favor.svg',
// colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
// height: 40.0,
// width: 40.0,
// ),
// Text(
// '${videoList[index]['starNum']}',
// style: TextStyle(color: Colors.white, fontSize: 12.0),
// ),
// ],
// ),
// 转发
GestureDetector(
child: Column(
children: [
SvgPicture.asset(
'assets/images/svg/share.svg',
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
height: 40.0,
width: 40.0,
),
],
),
onTap: () {
handleShare(index);
},
),
//举报
GestureDetector(
child: Column(
children: [
SvgPicture.asset(
'assets/images/svg/report.svg',
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
height: 40.0,
width: 40.0,
),
],
),
onTap: () {
// 举报
},
),
],
),
),
// 底部信息区域
Positioned(
bottom: 15.0,
left: 10.0,
right: 80.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'@${videoList[videoModuleController.videoPlayIndex.value]['nickname'] ?? '未知'}',
style: const TextStyle(color: Colors.white, fontSize: 16.0),
),
LayoutBuilder(
builder: (context, constraints) {
final text = videoList[videoModuleController.videoPlayIndex.value]['title'] ?? '未知';
// 先用 TextPainter 判断是否超过 3 行
final span = TextSpan(
text: text,
style: const TextStyle(color: Colors.white, fontSize: 14.0),
);
final tp = TextPainter(
text: span,
maxLines: 3,
textDirection: TextDirection.ltr,
);
tp.layout(maxWidth: constraints.maxWidth);
final isOverflow = tp.didExceedMaxLines;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
text,
maxLines: videoList[videoModuleController.videoPlayIndex.value]['expanded'] ? null : 3,
overflow:
videoList[videoModuleController.videoPlayIndex.value]['expanded'] ? TextOverflow.visible : TextOverflow.ellipsis,
style: const TextStyle(color: Colors.white, fontSize: 14.0),
),
if (isOverflow)
Padding(
padding: const EdgeInsets.only(top: 6.0),
child: GestureDetector(
onTap: () {
setState(() {
videoList[videoModuleController.videoPlayIndex.value]['expanded'] =
!videoList[videoModuleController.videoPlayIndex.value]['expanded'];
});
},
child: Text(
videoList[videoModuleController.videoPlayIndex.value]['expanded'] ? '收起' : '展开更多',
textAlign: TextAlign.right,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
),
),
],
);
},
),
],
)),
// mini播放进度条
Positioned(
bottom: 0.0,
left: 6.0,
right: 6.0,
child: Visibility(
visible: videoModuleController.videoPlayIndex.value == index && position > Duration.zero,
child: Listener(
child: SliderTheme(
data: SliderThemeData(
trackHeight: sliderDraging ? 6.0 : 2.0,
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 4.0), // 调整滑块的大小
// trackShape: RectangularSliderTrackShape(), // 使用矩形轨道形状
overlayShape: RoundSliderOverlayShape(overlayRadius: 0), // 去掉Slider默认上下边距间隙
inactiveTrackColor: Colors.white24, // 设置非活动进度条的颜色
activeTrackColor: Colors.white, // 设置活动进度条的颜色
thumbColor: Colors.white, // 设置滑块的颜色
overlayColor: Colors.transparent, // 设置滑块覆盖层的颜色
),
child: Slider(
value: sliderValue,
onChanged: (value) async {
// debugPrint('当前视频播放时间$value');
setState(() {
sliderValue = value;
});
// 跳转播放时间
await player.seek(duration * value.clamp(0.0, 1.0));
},
onChangeEnd: (value) async {
setState(() {
sliderDraging = false;
});
// 继续播放
if (!player.state.playing) {
await player.play();
}
},
),
),
onPointerMove: (e) {
setState(() {
sliderDraging = true;
});
},
),
),
),
// 播放位置指示器
Positioned(
bottom: 100.0,
left: 10.0,
right: 10.0,
child: Visibility(
visible: sliderDraging,
child: DefaultTextStyle(
style: TextStyle(color: Colors.white54, fontSize: 18.0, fontFamily: 'Arial'),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8.0,
children: [
Text(position.label(reference: duration), style: TextStyle(color: Colors.white)),
Text('/', style: TextStyle(fontSize: 14.0)),
Text(duration.label(reference: duration)),
],
),
)),
),
],
);
},
),
/// 固定层
// 红包广告,先不做
// Ads(),
],
),
),
],
),
);
}
}