mod: 动态评论、二级评论展示

This commit is contained in:
guozhigq
2023-07-23 17:26:50 +08:00
parent 8fe0215fbc
commit bcc6431ec5
9 changed files with 117 additions and 131 deletions

View File

@ -306,7 +306,7 @@ class VideoHttp {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return {'status': true, 'data': res.data['data']}; return {'status': true, 'data': res.data['data']};
} else { } else {
return {'status': false, 'data': []}; return {'status': false, 'data': [], 'msg': res.data['message']};
} }
} }

View File

@ -28,7 +28,8 @@ enum ReplyType {
ticket, ticket,
// 音频 // 音频
audio, audio,
// 风纪委员会
unset3,
// 点评 // 点评
comment, comment,
// 动态 // 动态

View File

@ -72,7 +72,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
} }
void replyReply(replyItem) { void replyReply(replyItem) {
int oid = replyItem.replies!.first.oid; int oid = replyItem.oid;
int rpid = replyItem.rpid!; int rpid = replyItem.rpid!;
Get.to( Get.to(
() => Scaffold( () => Scaffold(
@ -85,6 +85,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
rpid: rpid, rpid: rpid,
source: 'dynamic', source: 'dynamic',
replyType: ReplyType.values[type], replyType: ReplyType.values[type],
firstFloor: replyItem,
), ),
), ),
); );
@ -217,7 +218,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
replyLevel: '1', replyLevel: '1',
replyReply: (replyItem) => replyReply: (replyItem) =>
replyReply(replyItem), replyReply(replyItem),
replyType: ReplyType.album, replyType: ReplyType.values[type],
); );
} }
}, },

View File

@ -27,7 +27,6 @@ class VideoReplyController extends GetxController {
int currentPage = 0; int currentPage = 0;
bool isLoadingMore = false; bool isLoadingMore = false;
RxString noMore = ''.obs; RxString noMore = ''.obs;
RxBool autoFocus = false.obs;
// 当前回复的回复 // 当前回复的回复
ReplyItemModel? currentReplyItem; ReplyItemModel? currentReplyItem;
// 回复来源 // 回复来源
@ -90,34 +89,4 @@ class VideoReplyController extends GetxController {
Future onLoad() async { Future onLoad() async {
queryReplyList(type: 'onLoad'); queryReplyList(type: 'onLoad');
} }
wakeUpReply() {
autoFocus.value = true;
}
// 发表评论
Future submitReplyAdd() async {
var result = await VideoHttp.replyAdd(
type: ReplyType.video,
oid: aid!,
root: replyLevel == '0'
? 0
: replyLevel == '1'
? currentReplyItem!.rpid
: rPid,
parent: replyLevel == '0'
? 0
: replyLevel == '1'
? currentReplyItem!.rpid
: currentReplyItem!.rpid,
message: replyLevel == '2'
? ' 回复 @${currentReplyItem!.member!.uname!} : 2楼31'
: '2楼31',
);
if (result['status']) {
SmartDialog.showToast(result['data']['success_toast']);
} else {
SmartDialog.showToast(result['message']);
}
}
} }

View File

@ -34,7 +34,6 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
late VideoReplyController _videoReplyController; late VideoReplyController _videoReplyController;
late AnimationController fabAnimationCtr; late AnimationController fabAnimationCtr;
// List<ReplyItemModel>? replyList;
Future? _futureBuilderFuture; Future? _futureBuilderFuture;
bool _isFabVisible = true; bool _isFabVisible = true;
String replyLevel = '1'; String replyLevel = '1';
@ -112,8 +111,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
_videoReplyController.replyLevel = '0'; _videoReplyController.replyLevel = '0';
} }
await Future.delayed(const Duration(microseconds: 100)); // await Future.delayed(const Duration(microseconds: 100));
_videoReplyController.wakeUpReply(); // _videoReplyController.wakeUpReply();
} }
// 展示二级回复 // 展示二级回复
@ -231,7 +230,6 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
isScrollControlled: true, isScrollControlled: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return VideoReplyNewDialog( return VideoReplyNewDialog(
replyLevel: '0',
oid: IdUtils.bv2av(Get.parameters['bvid']!), oid: IdUtils.bv2av(Get.parameters['bvid']!),
root: 0, root: 0,
parent: 0, parent: 0,

View File

@ -185,7 +185,7 @@ class ReplyItem extends StatelessWidget {
children: [ children: [
if (replyItem!.isTop!) if (replyItem!.isTop!)
WidgetSpan(child: UpTag(tagText: 'TOP')), WidgetSpan(child: UpTag(tagText: 'TOP')),
buildContent(context, replyItem!, replyReply, 1, null), buildContent(context, replyItem!, replyReply, null),
], ],
), ),
), ),
@ -194,7 +194,9 @@ class ReplyItem extends StatelessWidget {
// 操作区域 // 操作区域
bottonAction(context, replyItem!.replyControl), bottonAction(context, replyItem!.replyControl),
// 一楼的评论 // 一楼的评论
if (replyItem!.replies!.isNotEmpty && showReplyRow!) ...[ if ((replyItem!.replyControl!.isShow! ||
replyItem!.replies!.isNotEmpty) &&
showReplyRow!) ...[
Padding( Padding(
padding: const EdgeInsets.only(top: 5, bottom: 12), padding: const EdgeInsets.only(top: 5, bottom: 12),
child: ReplyItemRow( child: ReplyItemRow(
@ -262,16 +264,16 @@ class ReplyItem extends StatelessWidget {
isScrollControlled: true, isScrollControlled: true,
builder: (builder) { builder: (builder) {
return VideoReplyNewDialog( return VideoReplyNewDialog(
replyLevel: replyLevel,
oid: replyItem!.oid, oid: replyItem!.oid,
root: replyItem!.rpid, root: replyItem!.rpid,
parent: replyItem!.rpid, parent: replyItem!.rpid,
replyType: replyType, replyType: replyType,
replyItem: replyItem,
); );
}, },
).then((value) => { ).then((value) => {
// 完成评论,数据添加 // 完成评论,数据添加
if (value['data'] != null) if (value != null && value['data'] != null)
{ {
addReply!(value['data']) addReply!(value['data'])
// replyControl.replies.add(value['data']), // replyControl.replies.add(value['data']),
@ -339,58 +341,57 @@ class ReplyItemRow extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
for (var i = 0; i < replies!.length; i++) ...[ if (replies!.isNotEmpty)
InkWell( for (var i = 0; i < replies!.length; i++) ...[
// 一楼点击评论展开评论详情 InkWell(
onTap: () => replyReply!(replyItem), // 一楼点击评论展开评论详情
child: Container( onTap: () => replyReply!(replyItem),
width: double.infinity, child: Container(
padding: EdgeInsets.fromLTRB( width: double.infinity,
8, padding: EdgeInsets.fromLTRB(
i == 0 && (extraRow == 1 || replies!.length > 1) ? 8 : 5, 8,
8, i == 0 && (extraRow == 1 || replies!.length > 1) ? 8 : 5,
i == 0 && (extraRow == 1 || replies!.length > 1) ? 5 : 6, 8,
), i == 0 && (extraRow == 1 || replies!.length > 1) ? 5 : 6,
child: Text.rich( ),
overflow: extraRow == 1 child: Text.rich(
? TextOverflow.ellipsis overflow: TextOverflow.ellipsis,
: TextOverflow.visible, maxLines: 2,
maxLines: extraRow == 1 ? 2 : null, TextSpan(
TextSpan( children: [
children: [ TextSpan(
TextSpan( text: replies![i].member.uname + ' ',
text: replies![i].member.uname + ' ', style: TextStyle(
style: TextStyle( fontSize: Theme.of(context)
fontSize: Theme.of(context) .textTheme
.textTheme .titleSmall!
.titleSmall! .fontSize,
.fontSize, color: Theme.of(context).colorScheme.primary,
color: Theme.of(context).colorScheme.primary, ),
recognizer: TapGestureRecognizer()
..onTap = () {
String heroTag =
Utils.makeHeroTag(replies![i].member.mid);
Get.toNamed(
'/member?mid=${replies![i].member.mid}',
arguments: {
'face': replies![i].member.avatar,
'heroTag': heroTag
});
},
), ),
recognizer: TapGestureRecognizer() if (replies![i].isUp)
..onTap = () { WidgetSpan(
String heroTag = child: UpTag(),
Utils.makeHeroTag(replies![i].member.mid); ),
Get.toNamed( buildContent(
'/member?mid=${replies![i].member.mid}', context, replies![i], replyReply, replyItem),
arguments: { ],
'face': replies![i].member.avatar, ),
'heroTag': heroTag
});
},
),
if (replies![i].isUp)
WidgetSpan(
child: UpTag(),
),
buildContent(
context, replies![i], replyReply, 2, replyItem),
],
), ),
), ),
), )
) ],
],
if (extraRow == 1) if (extraRow == 1)
InkWell( InkWell(
// 一楼点击【共xx条回复】展开评论详情 // 一楼点击【共xx条回复】展开评论详情
@ -426,21 +427,23 @@ class ReplyItemRow extends StatelessWidget {
} }
InlineSpan buildContent( InlineSpan buildContent(
BuildContext context, replyItem, replyReply, level, fReplyItem) { BuildContext context, replyItem, replyReply, fReplyItem) {
// replyItem 当前回复内容 // replyItem 当前回复内容
// replyReply 查看二楼回复(回复详情)回调 // replyReply 查看二楼回复(回复详情)回调
// fReplyItem 父级回复内容,用作二楼回复(回复详情)展示 // fReplyItem 父级回复内容,用作二楼回复(回复详情)展示
var content = replyItem.content; var content = replyItem.content;
// if (content.emote.isEmpty && if (content.emote.isEmpty &&
// content.atNameToMid.isEmpty && content.atNameToMid.isEmpty &&
// content.jumpUrl.isEmpty && content.jumpUrl.isEmpty &&
// content.vote.isEmpty && content.vote.isEmpty &&
// content.pictures.isEmpty) { content.pictures.isEmpty) {
// return TextSpan( return TextSpan(
// text: content.message, text: content.message,
// recognizer: TapGestureRecognizer()..onTap = () => replyReply(fReplyItem), recognizer: TapGestureRecognizer()
// ); ..onTap =
// } () => replyReply(replyItem.root == 0 ? replyItem : fReplyItem),
);
}
List<InlineSpan> spanChilds = []; List<InlineSpan> spanChilds = [];
bool hasMatchMember = true; bool hasMatchMember = true;
@ -501,15 +504,16 @@ InlineSpan buildContent(
spanChilds.add(TextSpan( spanChilds.add(TextSpan(
text: matchStr, text: matchStr,
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = ..onTap = () =>
() => replyReply(level == 1 ? replyItem : fReplyItem))); replyReply(replyItem.root == 0 ? replyItem : fReplyItem)));
return matchStr; return matchStr;
} }
} else { } else {
spanChilds.add(TextSpan( spanChilds.add(TextSpan(
text: matchStr, text: matchStr,
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => replyReply(level == 1 ? replyItem : fReplyItem))); ..onTap = () =>
replyReply(replyItem.root == 0 ? replyItem : fReplyItem)));
return matchStr; return matchStr;
} }
return ''; return '';
@ -593,8 +597,8 @@ InlineSpan buildContent(
spanChilds.add(TextSpan( spanChilds.add(TextSpan(
text: str, text: str,
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = ..onTap = () => replyReply(
() => replyReply(level == 1 ? replyItem : fReplyItem))); replyItem.root == 0 ? replyItem : fReplyItem)));
return str; return str;
}, },
); );
@ -630,7 +634,8 @@ InlineSpan buildContent(
spanChilds.add(TextSpan( spanChilds.add(TextSpan(
text: str, text: str,
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => replyReply(level == 1 ? replyItem : fReplyItem))); ..onTap = () =>
replyReply(replyItem.root == 0 ? replyItem : fReplyItem)));
} }
return str; return str;
}, },

View File

@ -12,16 +12,16 @@ import 'package:pilipala/utils/storage.dart';
class VideoReplyNewDialog extends StatefulWidget { class VideoReplyNewDialog extends StatefulWidget {
int? oid; int? oid;
int? root; int? root;
String? replyLevel;
int? parent; int? parent;
ReplyType? replyType; ReplyType? replyType;
ReplyItemModel? replyItem;
VideoReplyNewDialog({ VideoReplyNewDialog({
this.oid, this.oid,
this.root, this.root,
this.replyLevel,
this.parent, this.parent,
this.replyType, this.replyType,
this.replyItem,
}); });
@override @override
@ -36,14 +36,12 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
double _keyboardHeight = 0.0; // 键盘高度 double _keyboardHeight = 0.0; // 键盘高度
final _debouncer = Debouncer(milliseconds: 100); // 设置延迟时间 final _debouncer = Debouncer(milliseconds: 100); // 设置延迟时间
bool ableClean = false; bool ableClean = false;
bool autoFocus = false;
Timer? timer; Timer? timer;
Box localCache = GStrorage.localCache; Box localCache = GStrorage.localCache;
late double sheetHeight; late double sheetHeight;
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
// 监听输入框聚焦 // 监听输入框聚焦
// replyContentFocusNode.addListener(_onFocus); // replyContentFocusNode.addListener(_onFocus);
@ -74,14 +72,18 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
oid: widget.oid!, oid: widget.oid!,
root: widget.root!, root: widget.root!,
parent: widget.parent!, parent: widget.parent!,
message: message, message: widget.replyItem != null && widget.replyItem!.root != 0
? ' 回复 @${widget.replyItem!.member!.uname!} : $message'
: message,
); );
if (result['status']) { if (result['status']) {
SmartDialog.showToast(result['data']['success_toast']); SmartDialog.showToast(result['data']['success_toast']);
Get.back(result: { Get.back(result: {
'data': ReplyItemModel.fromJson(result['data']['reply'], ''), 'data': ReplyItemModel.fromJson(result['data']['reply'], ''),
}); });
} else {} } else {
SmartDialog.showToast(result['msg']);
}
} }
@override @override
@ -103,6 +105,12 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
}); });
} }
@override
void dispose() {
_replyContentController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(

View File

@ -123,7 +123,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
addReply: (replyItem) { addReply: (replyItem) {
_videoReplyReplyController.replyList.add(replyItem); _videoReplyReplyController.replyList.add(replyItem);
}, },
replyType: ReplyType.video, replyType: widget.replyType,
), ),
), ),
SliverToBoxAdapter( SliverToBoxAdapter(
@ -167,16 +167,16 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
), ),
); );
} else { } else {
return Material( return ReplyItem(
child: ReplyItem( replyItem: _videoReplyReplyController
replyItem: _videoReplyReplyController .replyList[index],
.replyList[index], replyLevel: '2',
replyLevel: '2', showReplyRow: false,
showReplyRow: false, addReply: (replyItem) {
addReply: (replyItem) { _videoReplyReplyController.replyList
_videoReplyReplyController.replyList .add(replyItem);
.add(replyItem); },
}), replyType: widget.replyType,
); );
} }
}, },

View File

@ -122,9 +122,9 @@ class Utils {
return timeStr; return timeStr;
} }
if (formatType == 'list' && int.parse(DD) > DateTime.now().day - 2) { // if (formatType == 'list' && int.parse(DD) > DateTime.now().day - 2) {
return '昨天'; // return '昨天';
} // }
date = date date = date
.replaceAll('YY', YY) .replaceAll('YY', YY)
@ -133,8 +133,12 @@ class Utils {
.replaceAll('hh', hh) .replaceAll('hh', hh)
.replaceAll('mm', mm) .replaceAll('mm', mm)
.replaceAll('ss', ss); .replaceAll('ss', ss);
if (int.parse(DD) < DateTime.now().day) { if (int.parse(YY) == DateTime.now().year &&
return date.split(' ')[0]; int.parse(MM) == DateTime.now().month) {
// 当天
if (int.parse(DD) == DateTime.now().day) {
return date.split(' ')[1];
}
} }
return date; return date;
} }