feat: sort article search

This commit is contained in:
bggRGjQaUbCoE
2024-09-28 12:30:40 +08:00
parent 80f8c88d0d
commit 579ed0103a
3 changed files with 265 additions and 79 deletions

View File

@@ -78,6 +78,7 @@ class SearchHttp {
int? tids, int? tids,
int? orderSort, int? orderSort,
int? userType, int? userType,
int? categoryId,
}) async { }) async {
var reqData = { var reqData = {
'search_type': searchType.type, 'search_type': searchType.type,
@@ -90,6 +91,7 @@ class SearchHttp {
if (tids != null) 'tids': tids, if (tids != null) 'tids': tids,
if (orderSort != null) 'order_sort': orderSort, if (orderSort != null) 'order_sort': orderSort,
if (userType != null) 'user_type': userType, if (userType != null) 'user_type': userType,
if (categoryId != null) 'category_id': categoryId,
}; };
var res = await Request().get(Api.searchByType, data: reqData); var res = await Request().get(Api.searchByType, data: reqData);
if (res.data['code'] == 0 && res.data['data']['numPages'] > 0) { if (res.data['code'] == 0 && res.data['data']['numPages'] > 0) {

View File

@@ -17,6 +17,7 @@ class SearchPanelController extends CommonController {
int? tids; int? tids;
int? orderSort; int? orderSort;
int? userType; int? userType;
int? categoryId;
@override @override
void onInit() { void onInit() {
@@ -75,5 +76,6 @@ class SearchPanelController extends CommonController {
tids: tids, tids: tids,
orderSort: orderSort, orderSort: orderSort,
userType: userType, userType: userType,
categoryId: categoryId,
); );
} }

View File

@@ -1,4 +1,9 @@
import 'package:PiliPalaX/pages/search/widgets/search_text.dart';
import 'package:PiliPalaX/pages/search_panel/controller.dart';
import 'package:PiliPalaX/pages/video/detail/reply/view.dart'
show MySliverPersistentHeaderDelegate;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:PiliPalaX/common/constants.dart'; import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
@@ -6,12 +11,67 @@ import 'package:PiliPalaX/utils/utils.dart';
import '../../../utils/grid.dart'; import '../../../utils/grid.dart';
Widget searchArticlePanel(BuildContext context, ctr, list) { Widget searchArticlePanel(BuildContext context, searchPanelCtr, list) {
TextStyle textStyle = TextStyle( TextStyle textStyle = TextStyle(
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
color: Theme.of(context).colorScheme.outline); color: Theme.of(context).colorScheme.outline);
return CustomScrollView(controller: ctr.scrollController, slivers: [ final ctr = Get.put(ArticlePanelController());
SliverGrid(
return CustomScrollView(
controller: searchPanelCtr.scrollController,
slivers: [
SliverPersistentHeader(
pinned: false,
floating: true,
delegate: MySliverPersistentHeaderDelegate(
child: Container(
height: 40,
color: Theme.of(context).colorScheme.surface,
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
Obx(
() => Text(
'排序: ${ctr.orderFiltersList[ctr.currentOrderFilterval.value]['label']}',
maxLines: 1,
style:
TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
const Spacer(),
Obx(
() => Text(
'分区: ${ctr.zoneFiltersList[ctr.currentZoneFilterval.value]['label']}',
maxLines: 1,
style:
TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
const Spacer(),
SizedBox(
width: 32,
height: 32,
child: IconButton(
tooltip: '筛选',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () {
ctr.onShowFilterDialog(context, searchPanelCtr);
},
icon: Icon(
Icons.filter_list_outlined,
size: 18,
color: Theme.of(context).colorScheme.primary,
),
),
),
],
),
),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio( gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.safeSpace, mainAxisSpacing: StyleString.safeSpace,
crossAxisSpacing: StyleString.safeSpace, crossAxisSpacing: StyleString.safeSpace,
@@ -32,89 +92,211 @@ Widget searchArticlePanel(BuildContext context, ctr, list) {
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace), horizontal: StyleString.safeSpace),
child: LayoutBuilder(builder: (context, boxConstraints) { child: LayoutBuilder(
final double width = (boxConstraints.maxWidth - builder: (context, boxConstraints) {
StyleString.cardSpace * final double width = (boxConstraints.maxWidth -
6 / StyleString.cardSpace *
MediaQuery.textScalerOf(context).scale(1.0)) / 6 /
2; MediaQuery.textScalerOf(context).scale(1.0)) /
return Container( 2;
constraints: const BoxConstraints(minHeight: 88), return Container(
height: width / StyleString.aspectRatio, constraints: const BoxConstraints(minHeight: 88),
child: Row( height: width / StyleString.aspectRatio,
crossAxisAlignment: CrossAxisAlignment.start, child: Row(
children: <Widget>[ crossAxisAlignment: CrossAxisAlignment.start,
if (list[index].imageUrls != null && children: <Widget>[
list[index].imageUrls.isNotEmpty) if (list[index].imageUrls != null &&
AspectRatio( list[index].imageUrls.isNotEmpty)
aspectRatio: StyleString.aspectRatio, AspectRatio(
child: LayoutBuilder( aspectRatio: StyleString.aspectRatio,
builder: (context, boxConstraints) { child: LayoutBuilder(
double maxWidth = boxConstraints.maxWidth; builder: (context, boxConstraints) {
double maxHeight = boxConstraints.maxHeight; double maxWidth = boxConstraints.maxWidth;
return NetworkImgLayer( double maxHeight = boxConstraints.maxHeight;
width: maxWidth, return NetworkImgLayer(
height: maxHeight, width: maxWidth,
src: list[index].imageUrls.first, height: maxHeight,
); src: list[index].imageUrls.first,
}), );
), }),
Expanded( ),
child: Padding( Expanded(
padding: const EdgeInsets.fromLTRB(10, 2, 6, 0), child: Padding(
child: Column( padding: const EdgeInsets.fromLTRB(10, 2, 6, 0),
mainAxisSize: MainAxisSize.min, child: Column(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min,
children: [ crossAxisAlignment: CrossAxisAlignment.start,
RichText( children: [
maxLines: 2, RichText(
text: TextSpan( maxLines: 2,
children: [ text: TextSpan(
for (var i in list[index].title) ...[ children: [
TextSpan( for (var i in list[index].title) ...[
text: i['text'], TextSpan(
style: TextStyle( text: i['text'],
fontWeight: FontWeight.w400, style: TextStyle(
letterSpacing: 0.3, fontWeight: FontWeight.w400,
color: i['type'] == 'em' letterSpacing: 0.3,
? Theme.of(context) color: i['type'] == 'em'
.colorScheme ? Theme.of(context)
.primary .colorScheme
: Theme.of(context) .primary
.colorScheme : Theme.of(context)
.onSurface, .colorScheme
.onSurface,
),
), ),
), ]
] ],
),
),
const Spacer(),
Text(
Utils.dateFormat(list[index].pubTime,
formatType: 'detail'),
style: textStyle),
Row(
children: [
Text('${list[index].view}浏览',
style: textStyle),
Text('', style: textStyle),
Text('${list[index].reply}评论',
style: textStyle),
], ],
), ),
), ],
const Spacer(), ),
Text(
Utils.dateFormat(list[index].pubTime,
formatType: 'detail'),
style: textStyle),
Row(
children: [
Text('${list[index].view}浏览',
style: textStyle),
Text('', style: textStyle),
Text('${list[index].reply}评论',
style: textStyle),
],
),
],
), ),
), ),
), ],
], ),
), );
); },
}), ),
), ),
); );
}, },
childCount: list.length, childCount: list.length,
)) ),
]); ),
],
);
}
class ArticlePanelController extends GetxController {
List orderFiltersList = [
{'label': '综合排序', 'value': 0, 'order': 'totalrank'},
{'label': '最新发布', 'value': 1, 'order': 'pubdate'},
{'label': '最多点击', 'value': 2, 'order': 'click'},
{'label': '最多喜欢', 'value': 3, 'order': 'attention'},
{'label': '最多评论', 'value': 4, 'order': 'scores'},
];
List zoneFiltersList = [
{'label': '全部分区', 'value': 0, 'categoryId': 0},
{'label': '动画', 'value': 1, 'categoryId': 2},
{'label': '游戏', 'value': 2, 'categoryId': 1},
{'label': '影视', 'value': 3, 'categoryId': 28},
{'label': '生活', 'value': 4, 'categoryId': 3},
{'label': '兴趣', 'value': 5, 'categoryId': 29},
{'label': '轻小说', 'value': 6, 'categoryId': 16},
{'label': '科技', 'value': 7, 'categoryId': 17},
{'label': '笔记', 'value': 8, 'categoryId': 41},
];
RxInt currentOrderFilterval = 0.obs;
RxInt currentZoneFilterval = 0.obs;
onShowFilterDialog(
BuildContext context,
SearchPanelController searchPanelCtr,
) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (_) => SingleChildScrollView(
child: Container(
width: double.infinity,
padding: EdgeInsets.only(
top: 20,
left: 16,
right: 16,
bottom: 80 + MediaQuery.of(context).padding.bottom,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
const Text('排序', style: TextStyle(fontSize: 16)),
const SizedBox(height: 10),
Wrap(
spacing: 8,
runSpacing: 8,
children: orderFiltersList
.map(
(item) => SearchText(
searchText: item['label'],
onSelect: (_) async {
Get.back();
currentOrderFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr =
Get.find<SearchPanelController>(
tag: 'article${searchPanelCtr.keyword!}');
ctr.order.value = item['order'];
SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh();
SmartDialog.dismiss();
},
onLongSelect: (_) {},
bgColor: item['value'] == currentOrderFilterval.value
? Theme.of(context).colorScheme.primaryContainer
: null,
textColor: item['value'] == currentOrderFilterval.value
? Theme.of(context).colorScheme.onPrimaryContainer
: null,
),
)
.toList(),
),
const SizedBox(height: 20),
const Text('分区', style: TextStyle(fontSize: 16)),
const SizedBox(height: 10),
Wrap(
spacing: 8,
runSpacing: 8,
children: zoneFiltersList
.map(
(item) => SearchText(
searchText: item['label'],
onSelect: (_) async {
Get.back();
currentZoneFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr =
Get.find<SearchPanelController>(
tag: 'article${searchPanelCtr.keyword!}');
ctr.categoryId = item['categoryId'];
SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh();
SmartDialog.dismiss();
},
onLongSelect: (_) {},
bgColor: item['value'] == currentZoneFilterval.value
? Theme.of(context).colorScheme.primaryContainer
: null,
textColor: item['value'] == currentZoneFilterval.value
? Theme.of(context).colorScheme.onPrimaryContainer
: null,
),
)
.toList(),
),
],
),
),
),
);
}
} }