From dbfe85e7817c131d66bf9bee34f342cfba307bb0 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 23 Jul 2023 21:12:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8C=89=E6=8E=92=E5=BA=8F=E6=9F=A5?= =?UTF-8?q?=E7=9C=8B=E8=AF=84=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/reply.dart | 2 +- lib/models/common/reply_sort_type.dart | 6 + lib/pages/dynamics/deatil/controller.dart | 29 +++- lib/pages/dynamics/deatil/view.dart | 108 ++++++------- lib/pages/video/detail/reply/controller.dart | 32 +++- lib/pages/video/detail/reply/view.dart | 150 ++++++++++++++---- .../detail/reply/widgets/reply_item.dart | 4 +- 7 files changed, 237 insertions(+), 94 deletions(-) create mode 100644 lib/models/common/reply_sort_type.dart 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/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/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 698d7425..de40a43e 100644 --- a/lib/pages/dynamics/deatil/view.dart +++ b/lib/pages/dynamics/deatil/view.dart @@ -159,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)), + ), + ) ], ), ), @@ -194,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.values[type], - ); - } - }, - 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 24cfc977..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'; @@ -36,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']) { @@ -89,4 +98,25 @@ class VideoReplyController extends GetxController { Future onLoad() async { queryReplyList(type: 'onLoad'); } + + // 排序搜索评论 + 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 a1b5a2f2..22846166 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -146,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) { @@ -155,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 { // 请求错误 @@ -254,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 2dcf9648..656eab23 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -103,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: @@ -177,7 +177,7 @@ 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' ? 3 : 999, overflow: TextOverflow.ellipsis,