feat: 按排序查看评论

This commit is contained in:
guozhigq
2023-07-23 21:12:49 +08:00
parent bcc6431ec5
commit dbfe85e781
7 changed files with 237 additions and 94 deletions

View File

@ -12,7 +12,7 @@ class ReplyHttp {
'oid': oid, 'oid': oid,
'pn': pageNum, 'pn': pageNum,
'type': type, 'type': type,
'sort': 1, 'sort': sort,
}); });
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return { return {

View File

@ -0,0 +1,6 @@
enum ReplySortType { time, like, reply }
extension ReplySortTypeExtension on ReplySortType {
String get titles => ['最新评论', '最热评论', '回复最多'][index];
String get labels => ['最新', '最热', '最多回复'][index];
}

View File

@ -1,6 +1,6 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/reply.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/data.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
@ -16,6 +16,10 @@ class DynamicDetailController extends GetxController {
RxList<ReplyItemModel> replyList = [ReplyItemModel()].obs; RxList<ReplyItemModel> replyList = [ReplyItemModel()].obs;
RxInt acount = 0.obs; RxInt acount = 0.obs;
ReplySortType sortType = ReplySortType.time;
RxString sortTypeTitle = ReplySortType.time.titles.obs;
RxString sortTypeLabel = ReplySortType.time.labels.obs;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -35,6 +39,7 @@ class DynamicDetailController extends GetxController {
oid: oid!, oid: oid!,
pageNum: currentPage + 1, pageNum: currentPage + 1,
type: type!, type: type!,
sort: sortType.index,
); );
if (res['status']) { if (res['status']) {
res['data'] = ReplyData.fromJson(res['data']); res['data'] = ReplyData.fromJson(res['data']);
@ -42,7 +47,7 @@ class DynamicDetailController extends GetxController {
if (res['data'].replies.isNotEmpty) { if (res['data'].replies.isNotEmpty) {
currentPage = currentPage + 1; currentPage = currentPage + 1;
noMore.value = '加载中...'; noMore.value = '加载中...';
if (replyList.isEmpty) { if (res['data'].replies.isEmpty) {
noMore.value = '没有更多了'; noMore.value = '没有更多了';
return; return;
} }
@ -80,4 +85,24 @@ class DynamicDetailController extends GetxController {
isLoadingMore = false; isLoadingMore = false;
return res; 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');
}
} }

View File

@ -159,27 +159,16 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
), ),
const Text('条回复'), const Text('条回复'),
const Spacer(), const Spacer(),
// TextButton.icon( SizedBox(
// onPressed: () {}, height: 35,
// icon: const Icon( child: TextButton.icon(
// Icons.subject_rounded, onPressed: () =>
// size: 15, _dynamicDetailController!.queryBySort(),
// ), icon: const Icon(Icons.sort, size: 17),
// style: TextButton.styleFrom( label: Obx(() => Text(
// padding: const EdgeInsets.fromLTRB(12, 0, 12, 0), _dynamicDetailController!.sortTypeLabel.value)),
// foregroundColor: ),
// Theme.of(context).colorScheme.outline, )
// ),
// label: Text(
// '按时间',
// style: TextStyle(
// fontSize: Theme.of(context)
// .textTheme
// .titleSmall!
// .fontSize,
// ),
// ),
// ),
], ],
), ),
), ),
@ -194,38 +183,51 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
if (snapshot.data['status']) { if (snapshot.data['status']) {
// 请求成功 // 请求成功
return Obx( return Obx(
() => SliverList( () => _dynamicDetailController!.replyList.isEmpty
delegate: SliverChildBuilderDelegate( ? SliverList(
(context, index) { delegate:
if (index == SliverChildBuilderDelegate((context, index) {
_dynamicDetailController!.replyList.length) { return const VideoReplySkeleton();
return Container( }, childCount: 8),
padding: EdgeInsets.only( )
bottom: : SliverList(
MediaQuery.of(context).padding.bottom), delegate: SliverChildBuilderDelegate(
height: (context, index) {
MediaQuery.of(context).padding.bottom + 100, if (index ==
child: Center( _dynamicDetailController!
child: Obx(() => Text( .replyList.length) {
_dynamicDetailController!.noMore.value)), return Container(
), padding: EdgeInsets.only(
); bottom: MediaQuery.of(context)
} else { .padding
return ReplyItem( .bottom),
replyItem: height: MediaQuery.of(context)
_dynamicDetailController!.replyList[index], .padding
showReplyRow: true, .bottom +
replyLevel: '1', 100,
replyReply: (replyItem) => child: Center(
replyReply(replyItem), child: Obx(() => Text(
replyType: ReplyType.values[type], _dynamicDetailController!
); .noMore.value)),
} ),
}, );
childCount: } else {
_dynamicDetailController!.replyList.length + 1, return ReplyItem(
), replyItem: _dynamicDetailController!
), .replyList[index],
showReplyRow: true,
replyLevel: '1',
replyReply: (replyItem) =>
replyReply(replyItem),
replyType: ReplyType.values[type],
);
}
},
childCount:
_dynamicDetailController!.replyList.length +
1,
),
),
); );
} else { } else {
// 请求错误 // 请求错误

View File

@ -5,6 +5,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/reply.dart'; import 'package:pilipala/http/reply.dart';
import 'package:pilipala/http/video.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/common/reply_type.dart';
import 'package:pilipala/models/video/reply/data.dart'; import 'package:pilipala/models/video/reply/data.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
@ -36,11 +37,19 @@ class VideoReplyController extends GetxController {
// 默认回复主楼 // 默认回复主楼
String replyLevel = '0'; String replyLevel = '0';
ReplySortType sortType = ReplySortType.time;
RxString sortTypeTitle = ReplySortType.time.titles.obs;
RxString sortTypeLabel = ReplySortType.time.labels.obs;
Future queryReplyList({type = 'init'}) async { Future queryReplyList({type = 'init'}) async {
isLoadingMore = true; isLoadingMore = true;
var res = level == '1' var res = level == '1'
? await ReplyHttp.replyList( ? 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( : await ReplyHttp.replyReplyList(
oid: aid!, root: rpid!, pageNum: currentPage + 1, type: 1); oid: aid!, root: rpid!, pageNum: currentPage + 1, type: 1);
if (res['status']) { if (res['status']) {
@ -89,4 +98,25 @@ class VideoReplyController extends GetxController {
Future onLoad() async { Future onLoad() async {
queryReplyList(type: 'onLoad'); 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');
}
} }

View File

@ -146,7 +146,46 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
controller: _videoReplyController.scrollController, controller: _videoReplyController.scrollController,
key: const PageStorageKey<String>('评论'), key: const PageStorageKey<String>('评论'),
slivers: <Widget>[ slivers: <Widget>[
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<double> animation) {
return ScaleTransition(
scale: animation, child: child);
},
child: Text(
_videoReplyController.sortTypeTitle.value,
key: ValueKey<String>(
_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( FutureBuilder(
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (context, snapshot) { builder: (context, snapshot) {
@ -155,40 +194,51 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
if (data['status']) { if (data['status']) {
// 请求成功 // 请求成功
return Obx( return Obx(
() => SliverList( () => _videoReplyController.replyList.isEmpty
delegate: SliverChildBuilderDelegate( ? SliverList(
(context, index) { delegate: SliverChildBuilderDelegate(
if (index == (context, index) {
_videoReplyController.replyList.length) { return const VideoReplySkeleton();
return Container( }, childCount: 5),
padding: EdgeInsets.only( )
bottom: MediaQuery.of(context) : SliverList(
.padding delegate: SliverChildBuilderDelegate(
.bottom), (context, index) {
height: if (index ==
MediaQuery.of(context).padding.bottom + _videoReplyController
100, .replyList.length) {
child: Center( return Container(
child: Obx(() => Text( padding: EdgeInsets.only(
_videoReplyController.noMore.value)), bottom: MediaQuery.of(context)
), .padding
); .bottom),
} else { height: MediaQuery.of(context)
return ReplyItem( .padding
replyItem: .bottom +
_videoReplyController.replyList[index], 100,
showReplyRow: true, child: Center(
replyLevel: replyLevel, child: Obx(() => Text(
replyReply: (replyItem) => _videoReplyController
replyReply(replyItem), .noMore.value)),
replyType: ReplyType.video, ),
); );
} } else {
}, return ReplyItem(
childCount: replyItem: _videoReplyController
_videoReplyController.replyList.length + 1, .replyList[index],
), showReplyRow: true,
), replyLevel: replyLevel,
replyReply: (replyItem) =>
replyReply(replyItem),
replyType: ReplyType.video,
);
}
},
childCount:
_videoReplyController.replyList.length +
1,
),
),
); );
} else { } else {
// 请求错误 // 请求错误
@ -254,3 +304,33 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
); );
} }
} }
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子组件
//shrinkOffsetchild偏移值minExtent~maxExtent
//overlapsContentSliverPersistentHeader覆盖其他子组件返回true否则返回false
return child;
}
//SliverPersistentHeader最大高度
@override
double get maxExtent => _maxExtent;
//SliverPersistentHeader最小高度
@override
double get minExtent => _minExtent;
@override
bool shouldRebuild(covariant _MySliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}

View File

@ -103,7 +103,7 @@ class ReplyItem extends StatelessWidget {
replyItem!.member!.uname!, replyItem!.member!.uname!,
style: TextStyle( style: TextStyle(
color: replyItem!.isUp! || color: replyItem!.isUp! ||
replyItem!.member!.vip!['vipType'] > 0 replyItem!.member!.vip!['vipStatus'] > 0
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline, : Theme.of(context).colorScheme.outline,
fontSize: fontSize:
@ -177,7 +177,7 @@ class ReplyItem extends StatelessWidget {
focusNode: FocusNode(), focusNode: FocusNode(),
selectionControls: MaterialTextSelectionControls(), selectionControls: MaterialTextSelectionControls(),
child: Text.rich( child: Text.rich(
style: const TextStyle(height: 1.65), style: const TextStyle(height: 1.75),
maxLines: maxLines:
replyItem!.content!.isText! && replyLevel == '1' ? 3 : 999, replyItem!.content!.isText! && replyLevel == '1' ? 3 : 999,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,