mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: sort article search
This commit is contained in:
@@ -78,6 +78,7 @@ class SearchHttp {
|
||||
int? tids,
|
||||
int? orderSort,
|
||||
int? userType,
|
||||
int? categoryId,
|
||||
}) async {
|
||||
var reqData = {
|
||||
'search_type': searchType.type,
|
||||
@@ -90,6 +91,7 @@ class SearchHttp {
|
||||
if (tids != null) 'tids': tids,
|
||||
if (orderSort != null) 'order_sort': orderSort,
|
||||
if (userType != null) 'user_type': userType,
|
||||
if (categoryId != null) 'category_id': categoryId,
|
||||
};
|
||||
var res = await Request().get(Api.searchByType, data: reqData);
|
||||
if (res.data['code'] == 0 && res.data['data']['numPages'] > 0) {
|
||||
|
||||
@@ -17,6 +17,7 @@ class SearchPanelController extends CommonController {
|
||||
int? tids;
|
||||
int? orderSort;
|
||||
int? userType;
|
||||
int? categoryId;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
@@ -75,5 +76,6 @@ class SearchPanelController extends CommonController {
|
||||
tids: tids,
|
||||
orderSort: orderSort,
|
||||
userType: userType,
|
||||
categoryId: categoryId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:PiliPalaX/common/constants.dart';
|
||||
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
|
||||
@@ -6,12 +11,67 @@ import 'package:PiliPalaX/utils/utils.dart';
|
||||
|
||||
import '../../../utils/grid.dart';
|
||||
|
||||
Widget searchArticlePanel(BuildContext context, ctr, list) {
|
||||
Widget searchArticlePanel(BuildContext context, searchPanelCtr, list) {
|
||||
TextStyle textStyle = TextStyle(
|
||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||
color: Theme.of(context).colorScheme.outline);
|
||||
return CustomScrollView(controller: ctr.scrollController, slivers: [
|
||||
SliverGrid(
|
||||
final ctr = Get.put(ArticlePanelController());
|
||||
|
||||
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(
|
||||
mainAxisSpacing: StyleString.safeSpace,
|
||||
crossAxisSpacing: StyleString.safeSpace,
|
||||
@@ -32,89 +92,211 @@ Widget searchArticlePanel(BuildContext context, ctr, list) {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: StyleString.safeSpace),
|
||||
child: LayoutBuilder(builder: (context, boxConstraints) {
|
||||
final double width = (boxConstraints.maxWidth -
|
||||
StyleString.cardSpace *
|
||||
6 /
|
||||
MediaQuery.textScalerOf(context).scale(1.0)) /
|
||||
2;
|
||||
return Container(
|
||||
constraints: const BoxConstraints(minHeight: 88),
|
||||
height: width / StyleString.aspectRatio,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (list[index].imageUrls != null &&
|
||||
list[index].imageUrls.isNotEmpty)
|
||||
AspectRatio(
|
||||
aspectRatio: StyleString.aspectRatio,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
double maxWidth = boxConstraints.maxWidth;
|
||||
double maxHeight = boxConstraints.maxHeight;
|
||||
return NetworkImgLayer(
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
src: list[index].imageUrls.first,
|
||||
);
|
||||
}),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 2, 6, 0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RichText(
|
||||
maxLines: 2,
|
||||
text: TextSpan(
|
||||
children: [
|
||||
for (var i in list[index].title) ...[
|
||||
TextSpan(
|
||||
text: i['text'],
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
letterSpacing: 0.3,
|
||||
color: i['type'] == 'em'
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
final double width = (boxConstraints.maxWidth -
|
||||
StyleString.cardSpace *
|
||||
6 /
|
||||
MediaQuery.textScalerOf(context).scale(1.0)) /
|
||||
2;
|
||||
return Container(
|
||||
constraints: const BoxConstraints(minHeight: 88),
|
||||
height: width / StyleString.aspectRatio,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (list[index].imageUrls != null &&
|
||||
list[index].imageUrls.isNotEmpty)
|
||||
AspectRatio(
|
||||
aspectRatio: StyleString.aspectRatio,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
double maxWidth = boxConstraints.maxWidth;
|
||||
double maxHeight = boxConstraints.maxHeight;
|
||||
return NetworkImgLayer(
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
src: list[index].imageUrls.first,
|
||||
);
|
||||
}),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 2, 6, 0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RichText(
|
||||
maxLines: 2,
|
||||
text: TextSpan(
|
||||
children: [
|
||||
for (var i in list[index].title) ...[
|
||||
TextSpan(
|
||||
text: i['text'],
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
letterSpacing: 0.3,
|
||||
color: i['type'] == 'em'
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
: Theme.of(context)
|
||||
.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,
|
||||
))
|
||||
]);
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user