feat: 按排序查看评论
This commit is contained in:
@ -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 {
|
||||||
|
|||||||
6
lib/models/common/reply_sort_type.dart
Normal file
6
lib/models/common/reply_sort_type.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
enum ReplySortType { time, like, reply }
|
||||||
|
|
||||||
|
extension ReplySortTypeExtension on ReplySortType {
|
||||||
|
String get titles => ['最新评论', '最热评论', '回复最多'][index];
|
||||||
|
String get labels => ['最新', '最热', '最多回复'][index];
|
||||||
|
}
|
||||||
@ -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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,26 +183,38 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
|
|||||||
if (snapshot.data['status']) {
|
if (snapshot.data['status']) {
|
||||||
// 请求成功
|
// 请求成功
|
||||||
return Obx(
|
return Obx(
|
||||||
() => SliverList(
|
() => _dynamicDetailController!.replyList.isEmpty
|
||||||
|
? SliverList(
|
||||||
|
delegate:
|
||||||
|
SliverChildBuilderDelegate((context, index) {
|
||||||
|
return const VideoReplySkeleton();
|
||||||
|
}, childCount: 8),
|
||||||
|
)
|
||||||
|
: SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index ==
|
if (index ==
|
||||||
_dynamicDetailController!.replyList.length) {
|
_dynamicDetailController!
|
||||||
|
.replyList.length) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom:
|
bottom: MediaQuery.of(context)
|
||||||
MediaQuery.of(context).padding.bottom),
|
.padding
|
||||||
height:
|
.bottom),
|
||||||
MediaQuery.of(context).padding.bottom + 100,
|
height: MediaQuery.of(context)
|
||||||
|
.padding
|
||||||
|
.bottom +
|
||||||
|
100,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Obx(() => Text(
|
child: Obx(() => Text(
|
||||||
_dynamicDetailController!.noMore.value)),
|
_dynamicDetailController!
|
||||||
|
.noMore.value)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return ReplyItem(
|
return ReplyItem(
|
||||||
replyItem:
|
replyItem: _dynamicDetailController!
|
||||||
_dynamicDetailController!.replyList[index],
|
.replyList[index],
|
||||||
showReplyRow: true,
|
showReplyRow: true,
|
||||||
replyLevel: '1',
|
replyLevel: '1',
|
||||||
replyReply: (replyItem) =>
|
replyReply: (replyItem) =>
|
||||||
@ -223,7 +224,8 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
childCount:
|
childCount:
|
||||||
_dynamicDetailController!.replyList.length + 1,
|
_dynamicDetailController!.replyList.length +
|
||||||
|
1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,28 +194,38 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
if (data['status']) {
|
if (data['status']) {
|
||||||
// 请求成功
|
// 请求成功
|
||||||
return Obx(
|
return Obx(
|
||||||
() => SliverList(
|
() => _videoReplyController.replyList.isEmpty
|
||||||
|
? SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return const VideoReplySkeleton();
|
||||||
|
}, childCount: 5),
|
||||||
|
)
|
||||||
|
: SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index ==
|
if (index ==
|
||||||
_videoReplyController.replyList.length) {
|
_videoReplyController
|
||||||
|
.replyList.length) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.of(context)
|
bottom: MediaQuery.of(context)
|
||||||
.padding
|
.padding
|
||||||
.bottom),
|
.bottom),
|
||||||
height:
|
height: MediaQuery.of(context)
|
||||||
MediaQuery.of(context).padding.bottom +
|
.padding
|
||||||
|
.bottom +
|
||||||
100,
|
100,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Obx(() => Text(
|
child: Obx(() => Text(
|
||||||
_videoReplyController.noMore.value)),
|
_videoReplyController
|
||||||
|
.noMore.value)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return ReplyItem(
|
return ReplyItem(
|
||||||
replyItem:
|
replyItem: _videoReplyController
|
||||||
_videoReplyController.replyList[index],
|
.replyList[index],
|
||||||
showReplyRow: true,
|
showReplyRow: true,
|
||||||
replyLevel: replyLevel,
|
replyLevel: replyLevel,
|
||||||
replyReply: (replyItem) =>
|
replyReply: (replyItem) =>
|
||||||
@ -186,7 +235,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
childCount:
|
childCount:
|
||||||
_videoReplyController.replyList.length + 1,
|
_videoReplyController.replyList.length +
|
||||||
|
1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -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子组件
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user