diff --git a/lib/http/reply.dart b/lib/http/reply.dart index aec1f96b..fa196823 100644 --- a/lib/http/reply.dart +++ b/lib/http/reply.dart @@ -12,7 +12,7 @@ class ReplyHttp { 'oid': oid, 'pn': pageNum, 'type': type, - 'sort': 1, + 'sort': sort, }); if (res.data['code'] == 0) { return { diff --git a/lib/http/video.dart b/lib/http/video.dart index 48b99ec6..e0acdd72 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -306,7 +306,7 @@ class VideoHttp { if (res.data['code'] == 0) { return {'status': true, 'data': res.data['data']}; } else { - return {'status': false, 'data': []}; + return {'status': false, 'data': [], 'msg': res.data['message']}; } } diff --git a/lib/models/common/reply_sort_type.dart b/lib/models/common/reply_sort_type.dart new file mode 100644 index 00000000..7c203c13 --- /dev/null +++ b/lib/models/common/reply_sort_type.dart @@ -0,0 +1,6 @@ +enum ReplySortType { time, like, reply } + +extension ReplySortTypeExtension on ReplySortType { + String get titles => ['最新评论', '最热评论', '回复最多'][index]; + String get labels => ['最新', '最热', '最多回复'][index]; +} diff --git a/lib/models/common/reply_type.dart b/lib/models/common/reply_type.dart index eef9c202..7eb8ac63 100644 --- a/lib/models/common/reply_type.dart +++ b/lib/models/common/reply_type.dart @@ -28,7 +28,8 @@ enum ReplyType { ticket, // 音频 audio, - + // 风纪委员会 + unset3, // 点评 comment, // 动态 diff --git a/lib/models/video/reply/content.dart b/lib/models/video/reply/content.dart index 68b59768..ad1759ac 100644 --- a/lib/models/video/reply/content.dart +++ b/lib/models/video/reply/content.dart @@ -33,10 +33,7 @@ class ReplyContent { pictures = json['pictures'] ?? []; vote = json['vote'] ?? {}; richText = json['rich_text'] ?? {}; - isText = emote!.isEmpty && - atNameToMid!.isEmpty && - jumpUrl!.isEmpty && - vote!.isEmpty && - pictures!.isEmpty; + // 不包含@ 笔记 图片的时候,文字可折叠 + isText = atNameToMid!.isEmpty && vote!.isEmpty && pictures!.isEmpty; } } diff --git a/lib/pages/dynamics/deatil/controller.dart b/lib/pages/dynamics/deatil/controller.dart index ab422b67..22022ce2 100644 --- a/lib/pages/dynamics/deatil/controller.dart +++ b/lib/pages/dynamics/deatil/controller.dart @@ -1,6 +1,6 @@ import 'package:get/get.dart'; import 'package:pilipala/http/reply.dart'; -import 'package:pilipala/models/dynamics/result.dart'; +import 'package:pilipala/models/common/reply_sort_type.dart'; import 'package:pilipala/models/video/reply/data.dart'; import 'package:pilipala/models/video/reply/item.dart'; @@ -16,6 +16,10 @@ class DynamicDetailController extends GetxController { RxList replyList = [ReplyItemModel()].obs; RxInt acount = 0.obs; + ReplySortType sortType = ReplySortType.time; + RxString sortTypeTitle = ReplySortType.time.titles.obs; + RxString sortTypeLabel = ReplySortType.time.labels.obs; + @override void onInit() { super.onInit(); @@ -35,6 +39,7 @@ class DynamicDetailController extends GetxController { oid: oid!, pageNum: currentPage + 1, type: type!, + sort: sortType.index, ); if (res['status']) { res['data'] = ReplyData.fromJson(res['data']); @@ -42,7 +47,7 @@ class DynamicDetailController extends GetxController { if (res['data'].replies.isNotEmpty) { currentPage = currentPage + 1; noMore.value = '加载中...'; - if (replyList.isEmpty) { + if (res['data'].replies.isEmpty) { noMore.value = '没有更多了'; return; } @@ -80,4 +85,24 @@ class DynamicDetailController extends GetxController { isLoadingMore = false; return res; } + + // 排序搜索评论 + queryBySort() { + switch (sortType) { + case ReplySortType.time: + sortType = ReplySortType.like; + break; + case ReplySortType.like: + sortType = ReplySortType.reply; + break; + case ReplySortType.reply: + sortType = ReplySortType.time; + break; + default: + } + sortTypeTitle.value = sortType.titles; + sortTypeLabel.value = sortType.labels; + replyList.clear(); + queryReplyList(reqType: 'init'); + } } diff --git a/lib/pages/dynamics/deatil/view.dart b/lib/pages/dynamics/deatil/view.dart index a09fa367..de40a43e 100644 --- a/lib/pages/dynamics/deatil/view.dart +++ b/lib/pages/dynamics/deatil/view.dart @@ -72,7 +72,7 @@ class _DynamicDetailPageState extends State { } void replyReply(replyItem) { - int oid = replyItem.replies!.first.oid; + int oid = replyItem.oid; int rpid = replyItem.rpid!; Get.to( () => Scaffold( @@ -85,6 +85,7 @@ class _DynamicDetailPageState extends State { rpid: rpid, source: 'dynamic', replyType: ReplyType.values[type], + firstFloor: replyItem, ), ), ); @@ -158,27 +159,16 @@ class _DynamicDetailPageState extends State { ), const Text('条回复'), const Spacer(), - // TextButton.icon( - // onPressed: () {}, - // icon: const Icon( - // Icons.subject_rounded, - // size: 15, - // ), - // style: TextButton.styleFrom( - // padding: const EdgeInsets.fromLTRB(12, 0, 12, 0), - // foregroundColor: - // Theme.of(context).colorScheme.outline, - // ), - // label: Text( - // '按时间', - // style: TextStyle( - // fontSize: Theme.of(context) - // .textTheme - // .titleSmall! - // .fontSize, - // ), - // ), - // ), + SizedBox( + height: 35, + child: TextButton.icon( + onPressed: () => + _dynamicDetailController!.queryBySort(), + icon: const Icon(Icons.sort, size: 17), + label: Obx(() => Text( + _dynamicDetailController!.sortTypeLabel.value)), + ), + ) ], ), ), @@ -193,38 +183,51 @@ class _DynamicDetailPageState extends State { if (snapshot.data['status']) { // 请求成功 return Obx( - () => SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == - _dynamicDetailController!.replyList.length) { - return Container( - padding: EdgeInsets.only( - bottom: - MediaQuery.of(context).padding.bottom), - height: - MediaQuery.of(context).padding.bottom + 100, - child: Center( - child: Obx(() => Text( - _dynamicDetailController!.noMore.value)), - ), - ); - } else { - return ReplyItem( - replyItem: - _dynamicDetailController!.replyList[index], - showReplyRow: true, - replyLevel: '1', - replyReply: (replyItem) => - replyReply(replyItem), - replyType: ReplyType.album, - ); - } - }, - childCount: - _dynamicDetailController!.replyList.length + 1, - ), - ), + () => _dynamicDetailController!.replyList.isEmpty + ? SliverList( + delegate: + SliverChildBuilderDelegate((context, index) { + return const VideoReplySkeleton(); + }, childCount: 8), + ) + : SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == + _dynamicDetailController! + .replyList.length) { + return Container( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context) + .padding + .bottom), + height: MediaQuery.of(context) + .padding + .bottom + + 100, + child: Center( + child: Obx(() => Text( + _dynamicDetailController! + .noMore.value)), + ), + ); + } else { + return ReplyItem( + replyItem: _dynamicDetailController! + .replyList[index], + showReplyRow: true, + replyLevel: '1', + replyReply: (replyItem) => + replyReply(replyItem), + replyType: ReplyType.values[type], + ); + } + }, + childCount: + _dynamicDetailController!.replyList.length + + 1, + ), + ), ); } else { // 请求错误 diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index 5047036f..d10408a6 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -5,6 +5,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/http/reply.dart'; import 'package:pilipala/http/video.dart'; +import 'package:pilipala/models/common/reply_sort_type.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/data.dart'; import 'package:pilipala/models/video/reply/item.dart'; @@ -27,7 +28,6 @@ class VideoReplyController extends GetxController { int currentPage = 0; bool isLoadingMore = false; RxString noMore = ''.obs; - RxBool autoFocus = false.obs; // 当前回复的回复 ReplyItemModel? currentReplyItem; // 回复来源 @@ -37,11 +37,19 @@ class VideoReplyController extends GetxController { // 默认回复主楼 String replyLevel = '0'; + ReplySortType sortType = ReplySortType.time; + RxString sortTypeTitle = ReplySortType.time.titles.obs; + RxString sortTypeLabel = ReplySortType.time.labels.obs; + Future queryReplyList({type = 'init'}) async { isLoadingMore = true; var res = level == '1' ? await ReplyHttp.replyList( - oid: aid!, pageNum: currentPage + 1, type: 1) + oid: aid!, + pageNum: currentPage + 1, + type: ReplyType.video.index, + sort: sortType.index, + ) : await ReplyHttp.replyReplyList( oid: aid!, root: rpid!, pageNum: currentPage + 1, type: 1); if (res['status']) { @@ -91,33 +99,24 @@ class VideoReplyController extends GetxController { 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']); + // 排序搜索评论 + queryBySort() { + switch (sortType) { + case ReplySortType.time: + sortType = ReplySortType.like; + break; + case ReplySortType.like: + sortType = ReplySortType.reply; + break; + case ReplySortType.reply: + sortType = ReplySortType.time; + break; + default: } + sortTypeTitle.value = sortType.titles; + sortTypeLabel.value = sortType.labels; + currentPage = 0; + replyList.clear(); + queryReplyList(type: 'init'); } } diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 506e0f66..22846166 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -34,7 +34,6 @@ class _VideoReplyPanelState extends State late VideoReplyController _videoReplyController; late AnimationController fabAnimationCtr; - // List? replyList; Future? _futureBuilderFuture; bool _isFabVisible = true; String replyLevel = '1'; @@ -112,15 +111,15 @@ class _VideoReplyPanelState extends State _videoReplyController.replyLevel = '0'; } - await Future.delayed(const Duration(microseconds: 100)); - _videoReplyController.wakeUpReply(); + // await Future.delayed(const Duration(microseconds: 100)); + // _videoReplyController.wakeUpReply(); } // 展示二级回复 void replyReply(replyItem) { VideoDetailController videoDetailCtr = Get.find(tag: Get.arguments['heroTag']); - videoDetailCtr.oid = replyItem.replies!.first.oid; + videoDetailCtr.oid = replyItem.oid; videoDetailCtr.fRpid = replyItem.rpid!; videoDetailCtr.firstFloor = replyItem; videoDetailCtr.showReplyReplyPanel(); @@ -147,7 +146,46 @@ class _VideoReplyPanelState extends State controller: _videoReplyController.scrollController, key: const PageStorageKey('评论'), slivers: [ - const SliverToBoxAdapter(child: SizedBox(height: 12)), + SliverPersistentHeader( + pinned: false, + floating: true, + delegate: _MySliverPersistentHeaderDelegate( + child: Container( + color: Theme.of(context).colorScheme.background, + padding: const EdgeInsets.fromLTRB(12, 6, 10, 6), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Obx( + () => AnimatedSwitcher( + duration: const Duration(milliseconds: 400), + transitionBuilder: + (Widget child, Animation animation) { + return ScaleTransition( + scale: animation, child: child); + }, + child: Text( + _videoReplyController.sortTypeTitle.value, + key: ValueKey( + _videoReplyController.sortTypeTitle.value), + ), + ), + ), + SizedBox( + height: 35, + child: TextButton.icon( + onPressed: () => + _videoReplyController.queryBySort(), + icon: const Icon(Icons.sort, size: 17), + label: Obx(() => Text( + _videoReplyController.sortTypeLabel.value)), + ), + ) + ], + ), + ), + ), + ), FutureBuilder( future: _futureBuilderFuture, builder: (context, snapshot) { @@ -156,40 +194,51 @@ class _VideoReplyPanelState extends State if (data['status']) { // 请求成功 return Obx( - () => SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == - _videoReplyController.replyList.length) { - return Container( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context) - .padding - .bottom), - height: - MediaQuery.of(context).padding.bottom + - 100, - child: Center( - child: Obx(() => Text( - _videoReplyController.noMore.value)), - ), - ); - } else { - return ReplyItem( - replyItem: - _videoReplyController.replyList[index], - showReplyRow: true, - replyLevel: replyLevel, - replyReply: (replyItem) => - replyReply(replyItem), - replyType: ReplyType.video, - ); - } - }, - childCount: - _videoReplyController.replyList.length + 1, - ), - ), + () => _videoReplyController.replyList.isEmpty + ? SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return const VideoReplySkeleton(); + }, childCount: 5), + ) + : SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == + _videoReplyController + .replyList.length) { + return Container( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context) + .padding + .bottom), + height: MediaQuery.of(context) + .padding + .bottom + + 100, + child: Center( + child: Obx(() => Text( + _videoReplyController + .noMore.value)), + ), + ); + } else { + return ReplyItem( + replyItem: _videoReplyController + .replyList[index], + showReplyRow: true, + replyLevel: replyLevel, + replyReply: (replyItem) => + replyReply(replyItem), + replyType: ReplyType.video, + ); + } + }, + childCount: + _videoReplyController.replyList.length + + 1, + ), + ), ); } else { // 请求错误 @@ -231,7 +280,6 @@ class _VideoReplyPanelState extends State isScrollControlled: true, builder: (BuildContext context) { return VideoReplyNewDialog( - replyLevel: '0', oid: IdUtils.bv2av(Get.parameters['bvid']!), root: 0, parent: 0, @@ -256,3 +304,33 @@ class _VideoReplyPanelState extends State ); } } + +class _MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { + final double _minExtent = 45; + final double _maxExtent = 45; + final Widget child; + + _MySliverPersistentHeaderDelegate({required this.child}); + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + //创建child子组件 + //shrinkOffset:child偏移值minExtent~maxExtent + //overlapsContent:SliverPersistentHeader覆盖其他子组件返回true,否则返回false + return child; + } + + //SliverPersistentHeader最大高度 + @override + double get maxExtent => _maxExtent; + + //SliverPersistentHeader最小高度 + @override + double get minExtent => _minExtent; + + @override + bool shouldRebuild(covariant _MySliverPersistentHeaderDelegate oldDelegate) { + return true; + } +} diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index e690effc..656eab23 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -1,17 +1,12 @@ -import 'dart:developer'; - import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_meedu_media_kit/meedu_player.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/pages/video/detail/controller.dart'; -import 'package:pilipala/pages/video/detail/reply/index.dart'; import 'package:pilipala/pages/video/detail/replyNew/index.dart'; -import 'package:pilipala/pages/video/detail/replyReply/index.dart'; import 'package:pilipala/utils/utils.dart'; class ReplyItem extends StatelessWidget { @@ -33,66 +28,52 @@ class ReplyItem extends StatelessWidget { @override Widget build(BuildContext context) { - return InkWell( - onTap: () {}, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(12, 4, 8, 2), - child: content(context), - ), - // Divider( - // height: 1, - // indent: 52, - // endIndent: 10, - // color: Theme.of(context).dividerColor.withOpacity(0.08), - // ) - ], + return Material( + child: InkWell( + // 点击整个评论区 评论详情/回复 + onTap: () => replyReply!(replyItem), + child: Padding( + padding: const EdgeInsets.fromLTRB(12, 4, 8, 2), + child: content(context), + ), ), ); } Widget lfAvtar(context, heroTag) { return Container( - margin: const EdgeInsets.only(top: 5), - child: Stack( - children: [ - Hero( - tag: heroTag, - child: NetworkImgLayer( - src: replyItem!.member!.avatar, - width: 34, - height: 34, - type: 'avatar', - ), + margin: const EdgeInsets.only(top: 5), + child: Stack( + children: [ + Hero( + tag: heroTag, + child: NetworkImgLayer( + src: replyItem!.member!.avatar, + width: 34, + height: 34, + type: 'avatar', ), - if (replyItem!.member!.officialVerify != null && - replyItem!.member!.officialVerify!['type'] == 0) - Positioned( - right: 0, - bottom: 0, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(7), - color: Theme.of(context).colorScheme.background, - ), - child: Icon( - Icons.offline_bolt, - color: Theme.of(context).colorScheme.primary, - size: 16, - ), + ), + if (replyItem!.member!.officialVerify != null && + replyItem!.member!.officialVerify!['type'] == 0) + Positioned( + right: 0, + bottom: 0, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7), + color: Theme.of(context).colorScheme.background, + ), + child: Icon( + Icons.offline_bolt, + color: Theme.of(context).colorScheme.primary, + size: 16, ), ), - ], - ) - // child: - // NetworkImgLayer( - // src: replyItem!.member!.avatar, - // width: 30, - // height: 30, - // type: 'avatar', - // ), - ); + ), + ], + ), + ); } Widget content(context) { @@ -122,7 +103,7 @@ class ReplyItem extends StatelessWidget { replyItem!.member!.uname!, style: TextStyle( color: replyItem!.isUp! || - replyItem!.member!.vip!['vipType'] > 0 + replyItem!.member!.vip!['vipStatus'] > 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.outline, fontSize: @@ -196,15 +177,15 @@ class ReplyItem extends StatelessWidget { focusNode: FocusNode(), selectionControls: MaterialTextSelectionControls(), child: Text.rich( - style: const TextStyle(height: 1.65), + style: const TextStyle(height: 1.75), maxLines: - replyItem!.content!.isText! && replyLevel == '1' ? 6 : 999, + replyItem!.content!.isText! && replyLevel == '1' ? 3 : 999, overflow: TextOverflow.ellipsis, TextSpan( children: [ if (replyItem!.isTop!) WidgetSpan(child: UpTag(tagText: 'TOP')), - buildContent(context, replyItem!, replyReply), + buildContent(context, replyItem!, replyReply, null), ], ), ), @@ -212,10 +193,12 @@ class ReplyItem extends StatelessWidget { ), // 操作区域 bottonAction(context, replyItem!.replyControl), - const SizedBox(height: 3), - if (replyItem!.replies!.isNotEmpty && showReplyRow!) ...[ + // 一楼的评论 + if ((replyItem!.replyControl!.isShow! || + replyItem!.replies!.isNotEmpty) && + showReplyRow!) ...[ Padding( - padding: const EdgeInsets.only(top: 2, bottom: 12), + padding: const EdgeInsets.only(top: 5, bottom: 12), child: ReplyItemRow( replies: replyItem!.replies, replyControl: replyItem!.replyControl, @@ -281,16 +264,16 @@ class ReplyItem extends StatelessWidget { isScrollControlled: true, builder: (builder) { return VideoReplyNewDialog( - replyLevel: replyLevel, oid: replyItem!.oid, root: replyItem!.rpid, parent: replyItem!.rpid, replyType: replyType, + replyItem: replyItem, ); }, ).then((value) => { // 完成评论,数据添加 - if (value['data'] != null) + if (value != null && value['data'] != null) { addReply!(value['data']) // replyControl.replies.add(value['data']), @@ -358,58 +341,60 @@ class ReplyItemRow extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - for (var i = 0; i < replies!.length; i++) ...[ - InkWell( - onTap: () => replyReply!(replyItem), - child: Container( - width: double.infinity, - padding: EdgeInsets.fromLTRB( - 8, - i == 0 && (extraRow == 1 || replies!.length > 1) ? 8 : 5, - 8, - i == 0 && (extraRow == 1 || replies!.length > 1) ? 5 : 6, - ), - child: Text.rich( - overflow: extraRow == 1 - ? TextOverflow.ellipsis - : TextOverflow.visible, - maxLines: extraRow == 1 ? 2 : null, - TextSpan( - children: [ - TextSpan( - text: replies![i].member.uname + ' ', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .titleSmall! - .fontSize, - color: Theme.of(context).colorScheme.primary, + if (replies!.isNotEmpty) + for (var i = 0; i < replies!.length; i++) ...[ + InkWell( + // 一楼点击评论展开评论详情 + onTap: () => replyReply!(replyItem), + child: Container( + width: double.infinity, + padding: EdgeInsets.fromLTRB( + 8, + i == 0 && (extraRow == 1 || replies!.length > 1) ? 8 : 5, + 8, + i == 0 && (extraRow == 1 || replies!.length > 1) ? 5 : 6, + ), + child: Text.rich( + overflow: TextOverflow.ellipsis, + maxLines: 2, + TextSpan( + children: [ + TextSpan( + text: replies![i].member.uname + ' ', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .titleSmall! + .fontSize, + 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() - ..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 - }); - }, - ), - if (replies![i].isUp) - WidgetSpan( - child: UpTag(), - ), - buildContent(context, replies![i], replyReply), - ], + if (replies![i].isUp) + WidgetSpan( + child: UpTag(), + ), + buildContent( + context, replies![i], replyReply, replyItem), + ], + ), ), ), - ), - ) - ], + ) + ], if (extraRow == 1) InkWell( + // 一楼点击【共xx条回复】展开评论详情 onTap: () => replyReply!(replyItem), child: Container( width: double.infinity, @@ -441,7 +426,11 @@ class ReplyItemRow extends StatelessWidget { } } -InlineSpan buildContent(BuildContext context, replyItem, replyReply) { +InlineSpan buildContent( + BuildContext context, replyItem, replyReply, fReplyItem) { + // replyItem 当前回复内容 + // replyReply 查看二楼回复(回复详情)回调 + // fReplyItem 父级回复内容,用作二楼回复(回复详情)展示 var content = replyItem.content; if (content.emote.isEmpty && content.atNameToMid.isEmpty && @@ -450,7 +439,9 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) { content.pictures.isEmpty) { return TextSpan( text: content.message, - recognizer: TapGestureRecognizer()..onTap = () => replyReply(replyItem), + recognizer: TapGestureRecognizer() + ..onTap = + () => replyReply(replyItem.root == 0 ? replyItem : fReplyItem), ); } List spanChilds = []; @@ -510,11 +501,19 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) { ), ); } else { - spanChilds.add(TextSpan(text: matchStr)); + spanChilds.add(TextSpan( + text: matchStr, + recognizer: TapGestureRecognizer() + ..onTap = () => + replyReply(replyItem.root == 0 ? replyItem : fReplyItem))); return matchStr; } } else { - spanChilds.add(TextSpan(text: matchStr)); + spanChilds.add(TextSpan( + text: matchStr, + recognizer: TapGestureRecognizer() + ..onTap = () => + replyReply(replyItem.root == 0 ? replyItem : fReplyItem))); return matchStr; } return ''; @@ -595,7 +594,11 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) { return ''; }, onNonMatch: (String str) { - spanChilds.add(TextSpan(text: str)); + spanChilds.add(TextSpan( + text: str, + recognizer: TapGestureRecognizer() + ..onTap = () => replyReply( + replyItem.root == 0 ? replyItem : fReplyItem))); return str; }, ); @@ -628,7 +631,11 @@ InlineSpan buildContent(BuildContext context, replyItem, replyReply) { ); if (content.atNameToMid.isEmpty && content.jumpUrl.isEmpty) { - spanChilds.add(TextSpan(text: str)); + spanChilds.add(TextSpan( + text: str, + recognizer: TapGestureRecognizer() + ..onTap = () => + replyReply(replyItem.root == 0 ? replyItem : fReplyItem))); } return str; }, diff --git a/lib/pages/video/detail/replyNew/view.dart b/lib/pages/video/detail/replyNew/view.dart index 60fe93d0..ff390eed 100644 --- a/lib/pages/video/detail/replyNew/view.dart +++ b/lib/pages/video/detail/replyNew/view.dart @@ -12,16 +12,16 @@ import 'package:pilipala/utils/storage.dart'; class VideoReplyNewDialog extends StatefulWidget { int? oid; int? root; - String? replyLevel; int? parent; ReplyType? replyType; + ReplyItemModel? replyItem; VideoReplyNewDialog({ this.oid, this.root, - this.replyLevel, this.parent, this.replyType, + this.replyItem, }); @override @@ -36,14 +36,12 @@ class _VideoReplyNewDialogState extends State double _keyboardHeight = 0.0; // 键盘高度 final _debouncer = Debouncer(milliseconds: 100); // 设置延迟时间 bool ableClean = false; - bool autoFocus = false; Timer? timer; Box localCache = GStrorage.localCache; late double sheetHeight; @override void initState() { - // TODO: implement initState super.initState(); // 监听输入框聚焦 // replyContentFocusNode.addListener(_onFocus); @@ -74,14 +72,18 @@ class _VideoReplyNewDialogState extends State oid: widget.oid!, root: widget.root!, parent: widget.parent!, - message: message, + message: widget.replyItem != null && widget.replyItem!.root != 0 + ? ' 回复 @${widget.replyItem!.member!.uname!} : $message' + : message, ); if (result['status']) { SmartDialog.showToast(result['data']['success_toast']); Get.back(result: { 'data': ReplyItemModel.fromJson(result['data']['reply'], ''), }); - } else {} + } else { + SmartDialog.showToast(result['msg']); + } } @override @@ -103,6 +105,12 @@ class _VideoReplyNewDialogState extends State }); } + @override + void dispose() { + _replyContentController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Container( diff --git a/lib/pages/video/detail/replyReply/view.dart b/lib/pages/video/detail/replyReply/view.dart index 5c3f99c1..07dea00d 100644 --- a/lib/pages/video/detail/replyReply/view.dart +++ b/lib/pages/video/detail/replyReply/view.dart @@ -123,7 +123,7 @@ class _VideoReplyReplyPanelState extends State { addReply: (replyItem) { _videoReplyReplyController.replyList.add(replyItem); }, - replyType: ReplyType.video, + replyType: widget.replyType, ), ), SliverToBoxAdapter( @@ -167,16 +167,16 @@ class _VideoReplyReplyPanelState extends State { ), ); } else { - return Material( - child: ReplyItem( - replyItem: _videoReplyReplyController - .replyList[index], - replyLevel: '2', - showReplyRow: false, - addReply: (replyItem) { - _videoReplyReplyController.replyList - .add(replyItem); - }), + return ReplyItem( + replyItem: _videoReplyReplyController + .replyList[index], + replyLevel: '2', + showReplyRow: false, + addReply: (replyItem) { + _videoReplyReplyController.replyList + .add(replyItem); + }, + replyType: widget.replyType, ); } }, diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index ce49b625..4745e8c4 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -122,9 +122,9 @@ class Utils { return timeStr; } - if (formatType == 'list' && int.parse(DD) > DateTime.now().day - 2) { - return '昨天'; - } + // if (formatType == 'list' && int.parse(DD) > DateTime.now().day - 2) { + // return '昨天'; + // } date = date .replaceAll('YY', YY) @@ -133,8 +133,12 @@ class Utils { .replaceAll('hh', hh) .replaceAll('mm', mm) .replaceAll('ss', ss); - if (int.parse(DD) < DateTime.now().day) { - return date.split(' ')[0]; + if (int.parse(YY) == DateTime.now().year && + int.parse(MM) == DateTime.now().month) { + // 当天 + if (int.parse(DD) == DateTime.now().day) { + return date.split(' ')[1]; + } } return date; }