推荐视频评论和点赞

This commit is contained in:
cuiyouliang 2025-08-22 18:24:52 +08:00
parent a78acc0f5c
commit 6cec14448c
3 changed files with 577 additions and 326 deletions

View File

@ -8,6 +8,9 @@ class VideoApi {
// post // post
static const String myPublicList = '/app/vlog/myPublicList'; // static const String myPublicList = '/app/vlog/myPublicList'; //
static const String myLikedList = '/app/vlog/myLikedList'; // static const String myLikedList = '/app/vlog/myLikedList'; //
static const String videoCommentList = '/comment/list'; //
static const String doVideoComment = '/app/comment/publish'; //
static const String unlike = '/app/vlog/unlike'; // static const String unlike = '/app/vlog/unlike'; //
static const String totalLikedCounts = '/app/vlog/totalLikedCounts'; // static const String totalLikedCounts = '/app/vlog/totalLikedCounts'; //

View File

@ -1,4 +1,3 @@
///
library; library;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -7,11 +6,15 @@ import 'package:get/get.dart';
class PopupReply extends StatefulWidget { class PopupReply extends StatefulWidget {
const PopupReply({ const PopupReply({
super.key, super.key,
this.onChanged this.onChanged,
this.onSubmitted, // onSubmitted
this.hintText = '说点什么...',
}); });
// //
final ValueChanged? onChanged; final ValueChanged<String>? onChanged;
final ValueChanged<String>? onSubmitted; // onSubmitted
final String hintText;
@override @override
State<PopupReply> createState() => _PopupReplyState(); State<PopupReply> createState() => _PopupReplyState();
@ -31,6 +34,26 @@ class _PopupReplyState extends State<PopupReply> {
controller.dispose(); controller.dispose();
} }
//
void _handleSubmit() {
final text = controller.text.trim();
if (text.isNotEmpty) {
// onSubmitted
if (widget.onSubmitted != null) {
widget.onSubmitted!(text);
} else if (widget.onChanged != null) {
// onSubmitted使 onChanged
widget.onChanged!(text);
Get.back();
}
}
}
// onSubmitted String
void _onSubmitted(String value) {
_handleSubmit();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -62,7 +85,7 @@ class _PopupReplyState extends State<PopupReply> {
), ),
child: TextField( child: TextField(
decoration: InputDecoration( decoration: InputDecoration(
hintText: '说点什么...', hintText: widget.hintText,
isDense: true, isDense: true,
hoverColor: Colors.transparent, hoverColor: Colors.transparent,
contentPadding: EdgeInsets.all(10.0), contentPadding: EdgeInsets.all(10.0),
@ -74,11 +97,9 @@ class _PopupReplyState extends State<PopupReply> {
maxLines: null, maxLines: null,
controller: controller, controller: controller,
cursorColor: Color(0xFFFF5000), cursorColor: Color(0xFFFF5000),
onEditingComplete: () { onEditingComplete: _handleSubmit, // 使
widget.onChanged!(controller.text); onChanged: widget.onChanged, // onChanged
Get.back(); onSubmitted: _onSubmitted, //
},
onChanged: (value) {},
), ),
), ),
), ),
@ -91,10 +112,7 @@ class _PopupReplyState extends State<PopupReply> {
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)) RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
) )
), ),
onPressed: () { onPressed: _handleSubmit, // 使
widget.onChanged!(controller.text);
Get.back();
},
child: Text('发送',), child: Text('发送',),
), ),
], ],

View File

@ -45,16 +45,351 @@ class RecommendModule extends StatefulWidget {
@override @override
State<RecommendModule> createState() => _RecommendModuleState(); State<RecommendModule> createState() => _RecommendModuleState();
} }
class CommentBottomSheet extends StatefulWidget {
final int videoId;
const CommentBottomSheet({super.key, required this.videoId});
@override
_CommentBottomSheetState createState() => _CommentBottomSheetState();
}
class _CommentBottomSheetState extends State<CommentBottomSheet> {
//
int commentPage = 1;
final int commentPageSize = 10;
bool isLoadingMoreComments = false;
bool hasMoreComments = true;
List<Map<String, dynamic>> commentList = [];
int replyingCommentId = 0;
String replyingCommentUser = '';
@override
void initState() {
super.initState();
//
fetchComments(false);
}
Future<void> fetchComments(bool loadMore) async {
if (isLoadingMoreComments && !loadMore) return;
setState(() {
isLoadingMoreComments = true;
});
if (!loadMore) {
commentPage = 1;
hasMoreComments = true;
commentList.clear();
}
try {
final res = await Http.post(VideoApi.videoCommentList, data: {
'vlogId': widget.videoId,
'current': commentPage,
'size': commentPageSize,
});
logger.d('评论接口返回: ${json.encode(res)}');
if (res['code'] == 200 && res['data'] != null) {
final data = res['data'];
final List<Map<String, dynamic>> newComments =
List<Map<String, dynamic>>.from(data['records'] ?? []);
final int total = data['total'] ?? 0;
setState(() {
if (loadMore) {
commentList.addAll(newComments);
} else {
commentList = newComments;
}
hasMoreComments = commentList.length < total;
commentPage++;
});
logger.d('成功加载 ${newComments.length} 条评论,总共 $total');
}
} catch (e) {
logger.e('获取评论异常: $e');
} finally {
setState(() {
isLoadingMoreComments = false;
});
}
}
Future<void> postComment(String content, {int parentCommentId = 0}) async {
try {
final res = await Http.post(VideoApi.doVideoComment, data: {
'vlogId': widget.videoId,
'content': content,
'fatherCommentId': parentCommentId,
});
if (res['code'] == 0) {
//
fetchComments(false);
MyToast().tip(
title: '评论成功',
position: 'center',
type: 'success',
);
}
} catch (e) {
logger.i('发布评论失败: $e');
MyToast().tip(
title: '评论失败',
position: 'center',
type: 'error',
);
}
}
@override
Widget build(BuildContext 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: () {
Navigator.pop(context);
},
),
],
),
Text(
'${commentList.length}条评论',
style: TextStyle(fontSize: 12.0, fontWeight: FontWeight.w600),
),
],
),
),
Expanded(
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent &&
!isLoadingMoreComments &&
hasMoreComments) {
fetchComments(true);
}
return false;
},
child: commentList.isEmpty && !isLoadingMoreComments
? Center(
child: Text(
'暂无评论',
style: TextStyle(color: Colors.grey),
),
)
: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: commentList.length + (hasMoreComments ? 1 : 0),
itemBuilder: (context, index) {
if (index == commentList.length) {
return Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: isLoadingMoreComments
? CircularProgressIndicator()
: Text('没有更多评论了'),
),
);
}
final comment = commentList[index];
return ListTile(
isThreeLine: true,
leading: ClipRRect(
borderRadius: BorderRadius.circular(50.0),
child: NetworkOrAssetImage(
imageUrl: comment['commentUserFace'] ?? 'assets/images/avatar/default.png',
width: 30.0,
height: 30.0,
fit: BoxFit.cover,
),
),
title: Row(
children: [
Expanded(
child: Text(
comment['commentUserNickname'] ?? '未知用户',
style: TextStyle(
color: Colors.grey,
fontSize: 12.0,
),
),
),
SizedBox(width: 20.0),
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentUser = comment['commentUserNickname'] ?? '未知用户';
});
},
child: Icon(
Icons.reply,
color: Colors.black54,
size: 16.0,
),
),
],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.symmetric(vertical: 5.0),
child: Text(
comment['content'] ?? '',
style: TextStyle(
fontSize: 14.0,
),
),
),
if (comment['childCount'] > 0)
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentUser = comment['commentUserNickname'] ?? '未知用户';
});
},
child: 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(
'${comment['childCount']}回复',
style: TextStyle(fontSize: 12.0),
),
Icon(
Icons.arrow_forward_ios,
size: 10.0,
)
]),
),
),
Text(
'${comment['createTime']?.toString().substring(0, 10) ?? ''}',
style: TextStyle(color: Colors.grey, fontSize: 12.0),
),
],
),
);
},
),
),
),
if (replyingCommentId > 0)
Container(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
color: Colors.grey[100],
child: Row(
children: [
Text(
'回复 @$replyingCommentUser',
style: TextStyle(fontSize: 12.0, color: Colors.blue),
),
Spacer(),
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = 0;
replyingCommentUser = '';
});
},
child: Icon(Icons.close, size: 16.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(
replyingCommentId > 0 ? '回复 @$replyingCommentUser' : '说点什么...',
style: TextStyle(color: Colors.black54, fontSize: 14.0),
),
],
),
),
onTap: () {
Navigator.push(context, FadeRoute(child: PopupReply(
hintText: replyingCommentId > 0 ? '回复 @$replyingCommentUser' : '说点什么...',
onChanged: (value) {
debugPrint('评论内容: $value');
},
onSubmitted: (value) {
if (value.isNotEmpty) {
postComment(value, parentCommentId: replyingCommentId);
setState(() {
replyingCommentId = 0;
replyingCommentUser = '';
});
Navigator.pop(context);
}
},
)));
},
),
],
),
);
}
}
class _RecommendModuleState extends State<RecommendModule> { class _RecommendModuleState extends State<RecommendModule> {
VideoModuleController videoModuleController = Get.put(VideoModuleController()); VideoModuleController videoModuleController = Get.put(VideoModuleController());
final ChatController chatController = Get.find<ChatController>(); 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; int page = 1;
final int pageSize = 10; final int pageSize = 10;
@ -78,15 +413,17 @@ class _RecommendModuleState extends State<RecommendModule> {
late Duration duration = Duration.zero; // late Duration duration = Duration.zero; //
// //
List videoList = []; List videoList = [];
//
List commentList = [ //
{'avatar': 'assets/images/avatar/img01.jpg', 'name': 'Alice', 'desc': '用汗水浇灌希望,让努力铸就辉煌,你付出的每一刻,都是在靠近成功的彼岸。'}, int commentPage = 1;
{'avatar': 'assets/images/avatar/img02.jpg', 'name': '悟空', 'desc': '黑暗遮不住破晓的曙光,困境困不住奋进的脚步,勇往直前,你定能冲破阴霾。'}, final int commentPageSize = 10;
{'avatar': 'assets/images/avatar/img03.jpg', 'name': '木棉花', 'desc': '每一次跌倒都是为了下一次更有力地跃起,别放弃~'}, bool isLoadingMoreComments = false;
{'avatar': 'assets/images/avatar/img04.jpg', 'name': '狗仔', 'desc': '人生没有白走的路,每一步都算数,那些辛苦的过往,会在未来化作最美的勋章。'}, bool hasMoreComments = true;
{'avatar': 'assets/images/avatar/img05.jpg', 'name': '向日葵', 'desc': '以梦为马,不负韶华,握紧手中的笔,书写属于自己的热血传奇,让青春绽放光芒。'}, List<Map<String, dynamic>> commentList = [];
{'avatar': 'assets/images/avatar/img06.jpg', 'name': '健身女神', 'desc': '哪怕身处谷底,只要抬头仰望,便能看见漫天繁星,心怀希望,就能找到出路,奔赴美好。'}, int currentVideoId = 0;
]; int replyingCommentId = 0; // ID
String replyingCommentUser = ''; //
// //
List shareList = [ List shareList = [
{'icon': 'assets/images/share-wx.png', 'label': '好友'}, {'icon': 'assets/images/share-wx.png', 'label': '好友'},
@ -187,16 +524,12 @@ class _RecommendModuleState extends State<RecommendModule> {
final data = res['data']; final data = res['data'];
logger.d('关注用户的视频列表:$data'); logger.d('关注用户的视频列表:$data');
if (data == null || (data is List && data.isEmpty)) { if (data == null || (data is List && data.isEmpty)) {
// MyDialog.toast('没有更多了', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
return; return;
} }
if (data['records'] is List) { if (data['records'] is List) {
List videos = data['records']; List videos = data['records'];
for (var item in videos) { for (var item in videos) {
// print("喜欢:${item['likeCounts']}");
// print("评论:${item['commentsCounts']}");
// logger.i(item);
item['expanded'] = false; item['expanded'] = false;
} }
@ -236,209 +569,148 @@ class _RecommendModuleState extends State<RecommendModule> {
} }
} }
// fetchComments
Future<void> fetchComments(int videoId, {bool loadMore = false}) async {
//
if (isLoadingMoreComments && !loadMore) return;
setState(() {
isLoadingMoreComments = true;
});
try {
final res = await Http.post(VideoApi.videoCommentList, data: {
'vlogId': videoId,
'current': loadMore ? commentPage : 1,
'size': commentPageSize,
});
logger.d('评论接口返回: ${json.encode(res)}');
if (res['code'] == 200 && res['data'] != null) {
final data = res['data'];
final List<Map<String, dynamic>> newComments =
List<Map<String, dynamic>>.from(data['records'] ?? []);
final int total = data['total'] ?? 0;
setState(() {
if (loadMore) {
commentList.addAll(newComments);
} else {
commentList = newComments;
}
hasMoreComments = commentList.length < total;
commentPage = loadMore ? commentPage + 1 : 2; //
});
logger.d('成功加载 ${newComments.length} 条评论,总共 $total');
} else {
logger.e('获取评论失败: ${res['msg']}');
MyToast().tip(
title: '获取评论失败',
position: 'center',
type: 'error',
);
}
} catch (e) {
logger.e('获取评论异常: $e');
MyToast().tip(
title: '网络异常',
position: 'center',
type: 'error',
);
} finally {
setState(() {
isLoadingMoreComments = false;
});
}
}
//
Future<void> postComment(String content, {int parentCommentId = 0}) async {
try {
final res = await Http.post(VideoApi.doVideoComment, data: {
'vlogId': currentVideoId,
'content': content,
'fatherCommentId': parentCommentId,
});
if (res['code'] == 0) {
//
fetchComments(currentVideoId, loadMore: false);
MyToast().tip(
title: '评论成功',
position: 'center',
type: 'success',
);
}
} catch (e) {
logger.i('发布评论失败: $e');
MyToast().tip(
title: '评论失败',
position: 'center',
type: 'error',
);
}
}
//
Future<void> doUnLikeVideo(item) async {
logger.d('点击了点赞按钮$item');
try {
final res = await Http.post(VideoApi.unlike, data:{
'vlogId': item['id']
});
final resCode = res['code'];
if (resCode == 200) {
setState(() {
item['doILikeThisVlog'] = !item['doILikeThisVlog'];
});
}
} catch (e) {
logger.i('点击取消喜欢按钮报错: $e');
}
}
//
Future<void> doLikeVideo(item) async {
try {
final res = await Http.post(VideoApi.like, data:{
'vlogId': item['id']
});
final resCode = res['code'];
if (resCode == 200) {
setState(() {
item['doILikeThisVlog'] = !item['doILikeThisVlog'];
});
}
logger.i('点赞返回信息----------->: $res');
} catch (e) {
logger.i('点击喜欢按钮报错: $e');
}
}
// //
void handleComment(index) { void handleComment(index) {
// final videoIdStr = videoList[index]['id'].toString();
final videoId = int.tryParse(videoIdStr) ?? 0;
logger.i('点击了评论按钮$videoId');
showModalBottomSheet( showModalBottomSheet(
backgroundColor: Colors.white, backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(15.0))), shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(15.0))),
showDragHandle: false, showDragHandle: false,
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
isScrollControlled: true, // isScrollControlled: true,
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 3 / 4, // maxHeight: MediaQuery.of(context).size.height * 3 / 4,
), ),
context: context, context: context,
builder: (context) { builder: (context) {
return Material( return CommentBottomSheet(videoId: videoId);
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) { void handleShare(index) {
@ -493,19 +765,15 @@ class _RecommendModuleState extends State<RecommendModule> {
), ),
// //
Obx(() { SizedBox(
//
final filteredList = chatController.chatList.where((item) => item.conversation.conversationGroupList?.isEmpty == true).toList();
if (filteredList.isEmpty) return SizedBox.shrink();
return SizedBox(
height: 110, height: 110,
child: ListView.builder( child: ListView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: filteredList.length, itemCount: chatController.chatList.where((item) => item.conversation.conversationGroupList?.isEmpty == true).length,
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 20.0), padding: EdgeInsets.symmetric(horizontal: 0, vertical: 20.0),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final filteredList = chatController.chatList.where((item) => item.conversation.conversationGroupList?.isEmpty == true).toList();
return GestureDetector( return GestureDetector(
//
onTap: () => handlCoverClick(filteredList[index].conversation), onTap: () => handlCoverClick(filteredList[index].conversation),
child: Container( child: Container(
width: 64, width: 64,
@ -513,7 +781,6 @@ class _RecommendModuleState extends State<RecommendModule> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// Image.asset('${chatController.chatList[index].faceUrl}', width: 48.0),
NetworkOrAssetImage( NetworkOrAssetImage(
imageUrl: filteredList[index].faceUrl, imageUrl: filteredList[index].faceUrl,
width: 48.0, width: 48.0,
@ -531,8 +798,7 @@ class _RecommendModuleState extends State<RecommendModule> {
); );
}, },
), ),
); ),
}),
// //
SafeArea( SafeArea(
@ -607,7 +873,6 @@ class _RecommendModuleState extends State<RecommendModule> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// super.build(context);
return Container( return Container(
color: Colors.black, color: Colors.black,
child: Column( child: Column(
@ -617,15 +882,12 @@ class _RecommendModuleState extends State<RecommendModule> {
children: [ children: [
/// ///
PageView.builder( PageView.builder(
// ()
scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false), scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
controller: pageController, controller: pageController,
onPageChanged: (index) async { onPageChanged: (index) async {
//
videoModuleController.updateVideoPlayIndex(index); videoModuleController.updateVideoPlayIndex(index);
setState(() { setState(() {
// slider参数
sliderValue = 0.0; sliderValue = 0.0;
sliderDraging = false; sliderDraging = false;
position = Duration.zero; position = Duration.zero;
@ -633,18 +895,17 @@ class _RecommendModuleState extends State<RecommendModule> {
}); });
player.stop(); player.stop();
// await player.open(Media(videoList[index]['src']));
await player.open(Media(videoList[index]['url'])); await player.open(Media(videoList[index]['url']));
//
if (index == videoList.length - 2 && !isLoadingMore) { if (index == videoList.length - 2 && !isLoadingMore) {
await fetchVideoList(); // await fetchVideoList();
} }
}, },
itemCount: videoList.length, itemCount: videoList.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final videoWidth = videoList[index]['width'] ?? 1; final videoWidth = videoList[index]['width'] ?? 1;
final videoHeight = videoList[index]['height'] ?? 1; // 0 final videoHeight = videoList[index]['height'] ?? 1;
final isHorizontal = videoWidth > videoHeight; final isHorizontal = videoWidth > videoHeight;
final filteredList = chatController.chatList.where((item) => item.conversation.conversationGroupList?.isEmpty == true).toList();
return Stack( return Stack(
children: [ children: [
// //
@ -656,17 +917,14 @@ class _RecommendModuleState extends State<RecommendModule> {
child: GestureDetector( child: GestureDetector(
child: Stack( child: Stack(
children: [ children: [
//
Visibility( Visibility(
visible: videoModuleController.videoPlayIndex.value == index && position > Duration.zero, visible: videoModuleController.videoPlayIndex.value == index && position > Duration.zero,
child: Video( child: Video(
controller: videoController, controller: videoController,
fit: isHorizontal ? BoxFit.contain : BoxFit.cover, fit: isHorizontal ? BoxFit.contain : BoxFit.cover,
//
controls: NoVideoControls, controls: NoVideoControls,
), ),
), ),
// 0
AnimatedOpacity( AnimatedOpacity(
opacity: videoModuleController.videoPlayIndex.value == index && position > Duration(milliseconds: 100) ? 0.0 : 1.0, opacity: videoModuleController.videoPlayIndex.value == index && position > Duration(milliseconds: 100) ? 0.0 : 1.0,
duration: Duration(milliseconds: 50), duration: Duration(milliseconds: 50),
@ -678,7 +936,6 @@ class _RecommendModuleState extends State<RecommendModule> {
), ),
), ),
// /
StreamBuilder( StreamBuilder(
stream: player.stream.playing, stream: player.stream.playing,
builder: (context, playing) { builder: (context, playing) {
@ -715,7 +972,6 @@ class _RecommendModuleState extends State<RecommendModule> {
child: Column( child: Column(
spacing: 15.0, spacing: 15.0,
children: [ children: [
//
Stack( Stack(
children: [ children: [
SizedBox( SizedBox(
@ -737,7 +993,7 @@ class _RecommendModuleState extends State<RecommendModule> {
), ),
child: ClipOval( child: ClipOval(
child: NetworkOrAssetImage( child: NetworkOrAssetImage(
imageUrl: videoList[index]['avatar'], imageUrl: videoList[index]['commentUserFace'],
), ),
), ),
), ),
@ -770,7 +1026,6 @@ class _RecommendModuleState extends State<RecommendModule> {
), ),
], ],
), ),
//
GestureDetector( GestureDetector(
child: Column( child: Column(
children: [ children: [
@ -787,12 +1042,15 @@ class _RecommendModuleState extends State<RecommendModule> {
], ],
), ),
onTap: () { onTap: () {
setState(() { logger.d('点击了点赞按钮${videoList[index]['doILikeThisVlog']}');
videoList[index]['doILikeThisVlog'] = !videoList[index]['doILikeThisVlog']; if(videoList[index]['doILikeThisVlog'] == true){
}); logger.d('点击了点赞按钮${videoList[index]['doILikeThisVlog']}');
doUnLikeVideo(videoList[index]);
}else{
doLikeVideo(videoList[index]);
}
}, },
), ),
//
GestureDetector( GestureDetector(
child: Column( child: Column(
children: [ children: [
@ -812,21 +1070,6 @@ class _RecommendModuleState extends State<RecommendModule> {
handleComment(index); 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( GestureDetector(
child: Column( child: Column(
children: [ children: [
@ -842,7 +1085,6 @@ class _RecommendModuleState extends State<RecommendModule> {
handleShare(index); handleShare(index);
}, },
), ),
//
GestureDetector( GestureDetector(
child: Column( child: Column(
children: [ children: [
@ -861,7 +1103,6 @@ class _RecommendModuleState extends State<RecommendModule> {
], ],
), ),
), ),
//
Positioned( Positioned(
bottom: 15.0, bottom: 15.0,
left: 10.0, left: 10.0,
@ -870,13 +1111,12 @@ class _RecommendModuleState extends State<RecommendModule> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'@${videoList[videoModuleController.videoPlayIndex.value]['nickname'] ?? '未知'}', '@${videoList[videoModuleController.videoPlayIndex.value]['commentUserNickname'] ?? '未知'}',
style: const TextStyle(color: Colors.white, fontSize: 16.0), style: const TextStyle(color: Colors.white, fontSize: 16.0),
), ),
LayoutBuilder( LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
final text = videoList[videoModuleController.videoPlayIndex.value]['title'] ?? '未知'; final text = videoList[videoModuleController.videoPlayIndex.value]['title'] ?? '未知';
// TextPainter 3
final span = TextSpan( final span = TextSpan(
text: text, text: text,
style: const TextStyle(color: Colors.white, fontSize: 14.0), style: const TextStyle(color: Colors.white, fontSize: 14.0),
@ -926,7 +1166,6 @@ class _RecommendModuleState extends State<RecommendModule> {
), ),
], ],
)), )),
// mini播放进度条
Positioned( Positioned(
bottom: 0.0, bottom: 0.0,
left: 6.0, left: 6.0,
@ -937,29 +1176,25 @@ class _RecommendModuleState extends State<RecommendModule> {
child: SliderTheme( child: SliderTheme(
data: SliderThemeData( data: SliderThemeData(
trackHeight: sliderDraging ? 6.0 : 2.0, trackHeight: sliderDraging ? 6.0 : 2.0,
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 4.0), // thumbShape: RoundSliderThumbShape(enabledThumbRadius: 4.0),
// trackShape: RectangularSliderTrackShape(), // 使 overlayShape: RoundSliderOverlayShape(overlayRadius: 0),
overlayShape: RoundSliderOverlayShape(overlayRadius: 0), // Slider默认上下边距间隙 inactiveTrackColor: Colors.white24,
inactiveTrackColor: Colors.white24, // activeTrackColor: Colors.white,
activeTrackColor: Colors.white, // thumbColor: Colors.white,
thumbColor: Colors.white, // overlayColor: Colors.transparent,
overlayColor: Colors.transparent, //
), ),
child: Slider( child: Slider(
value: sliderValue, value: sliderValue,
onChanged: (value) async { onChanged: (value) async {
// debugPrint('当前视频播放时间$value');
setState(() { setState(() {
sliderValue = value; sliderValue = value;
}); });
//
await player.seek(duration * value.clamp(0.0, 1.0)); await player.seek(duration * value.clamp(0.0, 1.0));
}, },
onChangeEnd: (value) async { onChangeEnd: (value) async {
setState(() { setState(() {
sliderDraging = false; sliderDraging = false;
}); });
//
if (!player.state.playing) { if (!player.state.playing) {
await player.play(); await player.play();
} }
@ -974,7 +1209,6 @@ class _RecommendModuleState extends State<RecommendModule> {
), ),
), ),
), ),
//
Positioned( Positioned(
bottom: 100.0, bottom: 100.0,
left: 10.0, left: 10.0,
@ -998,10 +1232,6 @@ class _RecommendModuleState extends State<RecommendModule> {
); );
}, },
), ),
///
// 广,
// Ads(),
], ],
), ),
), ),