opt: get theme color

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-28 21:32:30 +08:00
parent 451a84e696
commit ca993df0c6
149 changed files with 4415 additions and 4803 deletions

View File

@@ -17,7 +17,6 @@ class SearchAllPanel extends CommonSearchPanel {
required super.keyword,
required super.tag,
required super.searchType,
super.hasHeader = false,
});
@override
@@ -36,22 +35,12 @@ class _SearchAllPanelState
tag: widget.searchType.name + widget.tag,
);
late final TextStyle pgcStyle = TextStyle(fontSize: 13);
late TextStyle userStyle;
@override
void didChangeDependencies() {
super.didChangeDependencies();
userStyle = TextStyle(
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
color: Theme.of(context).colorScheme.outline,
);
}
@override
Widget buildList(List<dynamic> list) {
Widget buildList(ThemeData theme, List<dynamic> list) {
return SliverPadding(
padding: const EdgeInsets.only(bottom: 80),
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom + 80,
),
sliver: SliverWaterfallFlow.extent(
maxCrossAxisExtent: Grid.smallCardWidth * 2,
crossAxisSpacing: StyleString.safeSpace,
@@ -76,7 +65,7 @@ class _SearchAllPanelState
List<SearchMBangumiItemModel>() => item.length == 1
? SizedBox(
height: 160,
child: SearchPgcItem(style: pgcStyle, item: item.first),
child: SearchPgcItem(item: item.first),
)
: SizedBox(
height: Grid.smallCardWidth / 2 / 0.75 +
@@ -103,7 +92,6 @@ class _SearchAllPanelState
SearchUserItemModel() => Padding(
padding: const EdgeInsets.only(bottom: 5),
child: SearchUserItem(
style: userStyle,
item: item,
),
),

View File

@@ -69,83 +69,87 @@ class SearchArticleController
constraints: BoxConstraints(
maxWidth: min(640, min(Get.width, Get.height)),
),
builder: (context) => SingleChildScrollView(
child: Container(
width: double.infinity,
padding: EdgeInsets.only(
top: 20,
left: 16,
right: 16,
bottom: 80 + MediaQuery.of(context).padding.bottom,
builder: (context) {
final theme = Theme.of(context);
return 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(
text: item['label'],
onTap: (_) async {
Get.back();
currentOrderFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
order.value = item['order'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor: item['value'] == currentOrderFilterval.value
? theme.colorScheme.secondaryContainer
: null,
textColor:
item['value'] == currentOrderFilterval.value
? theme.colorScheme.onSecondaryContainer
: 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(
text: item['label'],
onTap: (_) async {
Get.back();
currentZoneFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
categoryId = item['categoryId'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor: item['value'] == currentZoneFilterval.value
? theme.colorScheme.secondaryContainer
: null,
textColor: item['value'] == currentZoneFilterval.value
? theme.colorScheme.onSecondaryContainer
: null,
),
)
.toList(),
),
],
),
),
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(
text: item['label'],
onTap: (_) async {
Get.back();
currentOrderFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
order.value = item['order'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor: item['value'] == currentOrderFilterval.value
? Theme.of(context).colorScheme.secondaryContainer
: null,
textColor: item['value'] == currentOrderFilterval.value
? Theme.of(context).colorScheme.onSecondaryContainer
: 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(
text: item['label'],
onTap: (_) async {
Get.back();
currentZoneFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
categoryId = item['categoryId'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor: item['value'] == currentZoneFilterval.value
? Theme.of(context).colorScheme.secondaryContainer
: null,
textColor: item['value'] == currentZoneFilterval.value
? Theme.of(context).colorScheme.onSecondaryContainer
: null,
),
)
.toList(),
),
],
),
),
),
);
},
);
}
}

View File

@@ -1,13 +1,9 @@
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/search/result.dart';
import 'package:PiliPlus/pages/search_panel/article/controller.dart';
import 'package:PiliPlus/pages/search_panel/article/widgets/item.dart';
import 'package:PiliPlus/pages/search_panel/view.dart';
import 'package:PiliPlus/utils/grid.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -17,7 +13,6 @@ class SearchArticlePanel extends CommonSearchPanel {
required super.keyword,
required super.tag,
required super.searchType,
super.hasHeader = true,
});
@override
@@ -36,191 +31,78 @@ class _SearchArticlePanelState extends CommonSearchPanelState<
tag: widget.searchType.name + widget.tag,
);
late TextStyle textStyle;
@override
void didChangeDependencies() {
super.didChangeDependencies();
textStyle = TextStyle(
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
color: Theme.of(context).colorScheme.outline,
);
}
@override
Widget buildHeader(LoadingState<List<SearchArticleItemModel>?> loadingState) {
if (loadingState is Success) {
return SliverPersistentHeader(
pinned: false,
floating: true,
delegate: CustomSliverPersistentHeaderDelegate(
extent: 40,
bgColor: Theme.of(context).colorScheme.surface,
child: Container(
height: 40,
padding: const EdgeInsets.only(left: 25, right: 12),
child: Row(
children: [
Obx(
() => Text(
'排序: ${controller.orderFiltersList[controller.currentOrderFilterval.value]['label']}',
maxLines: 1,
style:
TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
const Spacer(),
Obx(
() => Text(
'分区: ${controller.zoneFiltersList[controller.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: () {
controller.onShowFilterDialog(context);
},
icon: Icon(
Icons.filter_list_outlined,
size: 18,
color: Theme.of(context).colorScheme.primary,
Widget buildList(ThemeData theme, List<SearchArticleItemModel> list) {
return SliverMainAxisGroup(
slivers: [
SliverPersistentHeader(
pinned: false,
floating: true,
delegate: CustomSliverPersistentHeaderDelegate(
extent: 40,
bgColor: theme.colorScheme.surface,
child: Container(
height: 40,
padding: const EdgeInsets.only(left: 25, right: 12),
child: Row(
children: [
Obx(
() => Text(
'排序: ${controller.orderFiltersList[controller.currentOrderFilterval.value]['label']}',
maxLines: 1,
style: TextStyle(color: theme.colorScheme.outline),
),
),
),
],
const Spacer(),
Obx(
() => Text(
'分区: ${controller.zoneFiltersList[controller.currentZoneFilterval.value]['label']}',
maxLines: 1,
style: TextStyle(color: theme.colorScheme.outline),
),
),
const Spacer(),
SizedBox(
width: 32,
height: 32,
child: IconButton(
tooltip: '筛选',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () {
controller.onShowFilterDialog(context);
},
icon: Icon(
Icons.filter_list_outlined,
size: 18,
color: theme.colorScheme.primary,
),
),
),
],
),
),
),
),
);
}
return const SliverToBoxAdapter();
}
late final TextStyle style = TextStyle(fontSize: 13);
@override
Widget buildList(List<SearchArticleItemModel> list) {
return SliverPadding(
padding: const EdgeInsets.only(bottom: 80),
sliver: SliverGrid(
gridDelegate: Grid.videoCardHDelegate(context),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index == list.length - 1) {
controller.onLoadMore();
}
final item = list[index];
return InkWell(
onTap: () {
Get.toNamed(
'/articlePage',
parameters: {
'id': '${item.id}',
'type': 'read',
},
);
SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom + 80,
),
sliver: SliverGrid(
gridDelegate: Grid.videoCardHDelegate(context),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index == list.length - 1) {
controller.onLoadMore();
}
return SearchArticleItem(item: list[index]);
},
onLongPress: () => imageSaveDialog(
context: context,
title: item.title?.map((item) => item['text']).join() ?? '',
cover: item.imageUrls?.firstOrNull,
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
vertical: 5,
),
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 (item.imageUrls?.isNotEmpty == true)
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (context, boxConstraints) {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return NetworkImgLayer(
width: maxWidth,
height: maxHeight,
src: item.imageUrls?.firstOrNull,
);
}),
),
const SizedBox(width: 10),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text.rich(
maxLines: 2,
TextSpan(
children: [
for (var i in item.title!) ...[
TextSpan(
text: i['text'],
style: TextStyle(
color: i['type'] == 'em'
? Theme.of(context)
.colorScheme
.primary
: Theme.of(context)
.colorScheme
.onSurface,
),
),
]
],
),
),
const Spacer(),
Text(
Utils.dateFormat(item.pubTime,
formatType: 'detail'),
style: textStyle,
),
Row(
children: [
Text('${item.view}浏览', style: textStyle),
Text('', style: textStyle),
Text('${item.reply}评论', style: textStyle),
],
),
],
),
),
],
),
);
},
),
),
);
},
childCount: list.length,
childCount: list.length,
),
),
),
),
],
);
}
}

View File

@@ -0,0 +1,99 @@
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/models/search/result.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class SearchArticleItem extends StatelessWidget {
const SearchArticleItem({super.key, required this.item});
final SearchArticleItemModel item;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final textStyle = TextStyle(
fontSize: theme.textTheme.labelSmall!.fontSize,
color: theme.colorScheme.outline,
);
return InkWell(
onTap: () {
Get.toNamed(
'/articlePage',
parameters: {
'id': '${item.id}',
'type': 'read',
},
);
},
onLongPress: () => imageSaveDialog(
title: item.title?.map((item) => item['text']).join() ?? '',
cover: item.imageUrls?.firstOrNull,
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
vertical: 5,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (item.imageUrls?.isNotEmpty == true)
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(builder: (context, boxConstraints) {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return NetworkImgLayer(
width: maxWidth,
height: maxHeight,
src: item.imageUrls?.firstOrNull,
);
}),
),
const SizedBox(width: 10),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text.rich(
maxLines: 2,
TextSpan(
children: [
for (var i in item.title!) ...[
TextSpan(
text: i['text'],
style: TextStyle(
color: i['type'] == 'em'
? theme.colorScheme.primary
: theme.colorScheme.onSurface,
),
),
]
],
),
),
const Spacer(),
Text(
Utils.dateFormat(item.pubTime, formatType: 'detail'),
style: textStyle,
),
Row(
children: [
Text('${item.view}浏览', style: textStyle),
Text('', style: textStyle),
Text('${item.reply}评论', style: textStyle),
],
),
],
),
),
],
),
),
);
}
}

View File

@@ -32,12 +32,12 @@ class _SearchLivePanelState extends CommonSearchPanelState<SearchLivePanel,
);
@override
Widget buildList(List<SearchLiveItemModel> list) {
Widget buildList(ThemeData theme, List<SearchLiveItemModel> list) {
return SliverPadding(
padding: const EdgeInsets.only(
padding: EdgeInsets.only(
left: StyleString.safeSpace,
right: StyleString.safeSpace,
bottom: 80,
bottom: MediaQuery.paddingOf(context).bottom + 80,
),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(

View File

@@ -12,6 +12,7 @@ class LiveItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
elevation: 1,
clipBehavior: Clip.hardEdge,
@@ -21,7 +22,6 @@ class LiveItem extends StatelessWidget {
Get.toNamed('/liveRoom?roomid=${liveItem.roomid}');
},
onLongPress: () => imageSaveDialog(
context: context,
title: liveItem.title?.map((item) => item['text']).join() ?? '',
cover: liveItem.cover,
),
@@ -60,14 +60,14 @@ class LiveItem extends StatelessWidget {
}),
),
),
liveContent(context)
liveContent(theme)
],
),
),
);
}
Widget liveContent(BuildContext context) => Expanded(
Widget liveContent(ThemeData theme) => Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(9, 8, 9, 6),
child: Column(
@@ -83,8 +83,8 @@ class LiveItem extends StatelessWidget {
style: TextStyle(
letterSpacing: 0.3,
color: i['type'] == 'em'
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
? theme.colorScheme.primary
: theme.colorScheme.onSurface,
),
),
]
@@ -97,8 +97,8 @@ class LiveItem extends StatelessWidget {
liveItem.uname!,
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
color: Theme.of(context).colorScheme.outline,
fontSize: theme.textTheme.labelMedium!.fontSize,
color: theme.colorScheme.outline,
),
),
),

View File

@@ -30,12 +30,11 @@ class _SearchPgcPanelState extends CommonSearchPanelState<SearchPgcPanel,
tag: widget.searchType.name + widget.tag,
);
late final TextStyle style = TextStyle(fontSize: 13);
@override
Widget buildList(List<SearchMBangumiItemModel> list) {
Widget buildList(ThemeData theme, List<SearchMBangumiItemModel> list) {
return SliverPadding(
padding: const EdgeInsets.only(bottom: 80),
padding:
EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom + 80),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: Grid.smallCardWidth * 2,
@@ -46,7 +45,7 @@ class _SearchPgcPanelState extends CommonSearchPanelState<SearchPgcPanel,
if (index == list.length - 1) {
controller.onLoadMore();
}
return SearchPgcItem(style: style, item: list[index]);
return SearchPgcItem(item: list[index]);
},
childCount: list.length,
),

View File

@@ -10,21 +10,20 @@ import 'package:flutter/material.dart';
class SearchPgcItem extends StatelessWidget {
const SearchPgcItem({
super.key,
required this.style,
required this.item,
});
final TextStyle style;
final SearchMBangumiItemModel item;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final TextStyle style = TextStyle(fontSize: 13);
return InkWell(
onTap: () {
PageUtils.viewBangumi(seasonId: item.seasonId);
},
onLongPress: () => imageSaveDialog(
context: context,
title: item.title?.map((item) => item['text']).join() ?? '',
cover: item.cover,
),
@@ -60,21 +59,17 @@ class SearchPgcItem extends StatelessWidget {
const SizedBox(height: 4),
Text.rich(
TextSpan(
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface),
style: TextStyle(color: theme.colorScheme.onSurface),
children: [
for (var i in item.title!) ...[
TextSpan(
text: i['text'],
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.titleSmall!
.fontSize!,
fontSize: theme.textTheme.titleSmall!.fontSize!,
fontWeight: FontWeight.bold,
color: i['type'] == 'em'
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
? theme.colorScheme.primary
: theme.colorScheme.onSurface,
),
),
],

View File

@@ -41,85 +41,90 @@ class SearchUserController
constraints: BoxConstraints(
maxWidth: min(640, min(Get.width, Get.height)),
),
builder: (context) => SingleChildScrollView(
child: Container(
width: double.infinity,
padding: EdgeInsets.only(
top: 20,
left: 16,
right: 16,
bottom: 80 + MediaQuery.of(context).padding.bottom,
builder: (context) {
final theme = Theme.of(context);
return 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(
text: item['label'],
onTap: (_) async {
Get.back();
currentOrderFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
orderSort = item['orderSort'];
order.value = item['order'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor: item['value'] == currentOrderFilterval.value
? theme.colorScheme.secondaryContainer
: null,
textColor:
item['value'] == currentOrderFilterval.value
? theme.colorScheme.onSecondaryContainer
: null,
),
)
.toList(),
),
const SizedBox(height: 20),
const Text('用户分类', style: TextStyle(fontSize: 16)),
const SizedBox(height: 10),
Wrap(
spacing: 8,
runSpacing: 8,
children: userTypeFiltersList
.map(
(item) => SearchText(
text: item['label'],
onTap: (_) async {
Get.back();
currentUserTypeFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
userType = item['userType'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor:
item['value'] == currentUserTypeFilterval.value
? theme.colorScheme.secondaryContainer
: null,
textColor:
item['value'] == currentUserTypeFilterval.value
? theme.colorScheme.onSecondaryContainer
: null,
),
)
.toList(),
),
],
),
),
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(
text: item['label'],
onTap: (_) async {
Get.back();
currentOrderFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
orderSort = item['orderSort'];
order.value = item['order'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor: item['value'] == currentOrderFilterval.value
? Theme.of(context).colorScheme.secondaryContainer
: null,
textColor: item['value'] == currentOrderFilterval.value
? Theme.of(context).colorScheme.onSecondaryContainer
: null,
),
)
.toList(),
),
const SizedBox(height: 20),
const Text('用户分类', style: TextStyle(fontSize: 16)),
const SizedBox(height: 10),
Wrap(
spacing: 8,
runSpacing: 8,
children: userTypeFiltersList
.map(
(item) => SearchText(
text: item['label'],
onTap: (_) async {
Get.back();
currentUserTypeFilterval.value = item['value'];
SmartDialog.dismiss();
SmartDialog.showToast("${item['label']}」的筛选结果");
userType = item['userType'];
SmartDialog.showLoading(msg: 'loading');
await onReload();
SmartDialog.dismiss();
},
bgColor: item['value'] == currentUserTypeFilterval.value
? Theme.of(context).colorScheme.secondaryContainer
: null,
textColor: item['value'] ==
currentUserTypeFilterval.value
? Theme.of(context).colorScheme.onSecondaryContainer
: null,
),
)
.toList(),
),
],
),
),
),
);
},
);
}
}

View File

@@ -1,5 +1,4 @@
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/search/result.dart';
import 'package:PiliPlus/pages/search_panel/user/controller.dart';
import 'package:PiliPlus/pages/search_panel/user/widgets/item.dart';
@@ -14,7 +13,6 @@ class SearchUserPanel extends CommonSearchPanel {
required super.keyword,
required super.tag,
required super.searchType,
super.hasHeader = true,
});
@override
@@ -33,98 +31,82 @@ class _SearchUserPanelState extends CommonSearchPanelState<SearchUserPanel,
tag: widget.searchType.name + widget.tag,
);
late TextStyle style;
@override
void didChangeDependencies() {
super.didChangeDependencies();
style = TextStyle(
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
color: Theme.of(context).colorScheme.outline,
);
}
@override
Widget buildHeader(LoadingState<List<SearchUserItemModel>?> loadingState) {
if (loadingState is Success) {
return SliverPersistentHeader(
pinned: false,
floating: true,
delegate: CustomSliverPersistentHeaderDelegate(
extent: 40,
bgColor: Theme.of(context).colorScheme.surface,
child: Container(
height: 40,
padding: const EdgeInsets.only(left: 25, right: 12),
child: Row(
children: [
Obx(
() => Text(
'排序: ${controller.orderFiltersList[controller.currentOrderFilterval.value]['label']}',
maxLines: 1,
style:
TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
const Spacer(),
Obx(
() => Text(
'用户类型: ${controller.userTypeFiltersList[controller.currentUserTypeFilterval.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: () {
controller.onShowFilterDialog(context);
},
icon: Icon(
Icons.filter_list_outlined,
size: 18,
color: Theme.of(context).colorScheme.primary,
Widget buildList(ThemeData theme, List<SearchUserItemModel> list) {
return SliverMainAxisGroup(
slivers: [
SliverPersistentHeader(
pinned: false,
floating: true,
delegate: CustomSliverPersistentHeaderDelegate(
extent: 40,
bgColor: theme.colorScheme.surface,
child: Container(
height: 40,
padding: const EdgeInsets.only(left: 25, right: 12),
child: Row(
children: [
Obx(
() => Text(
'排序: ${controller.orderFiltersList[controller.currentOrderFilterval.value]['label']}',
maxLines: 1,
style: TextStyle(color: theme.colorScheme.outline),
),
),
),
],
const Spacer(),
Obx(
() => Text(
'用户类型: ${controller.userTypeFiltersList[controller.currentUserTypeFilterval.value]['label']}',
maxLines: 1,
style: TextStyle(color: theme.colorScheme.outline),
),
),
const Spacer(),
SizedBox(
width: 32,
height: 32,
child: IconButton(
tooltip: '筛选',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () {
controller.onShowFilterDialog(context);
},
icon: Icon(
Icons.filter_list_outlined,
size: 18,
color: theme.colorScheme.primary,
),
),
),
],
),
),
),
),
);
}
return const SliverToBoxAdapter();
}
@override
Widget buildList(List<SearchUserItemModel> list) {
return SliverPadding(
padding: const EdgeInsets.only(bottom: 80),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: Grid.smallCardWidth * 2,
mainAxisExtent: 66,
SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom + 80),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: Grid.smallCardWidth * 2,
mainAxisExtent: 66,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index == list.length - 1) {
controller.onLoadMore();
}
return SearchUserItem(
item: list[index],
);
},
childCount: list.length,
),
),
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index == list.length - 1) {
controller.onLoadMore();
}
return SearchUserItem(
style: style,
item: list[index],
);
},
childCount: list.length,
),
),
],
);
}
}

View File

@@ -7,16 +7,19 @@ import 'package:get/get.dart';
class SearchUserItem extends StatelessWidget {
const SearchUserItem({
super.key,
required this.style,
required this.item,
});
final TextStyle style;
final SearchUserItemModel item;
@override
Widget build(BuildContext context) {
String heroTag = Utils.makeHeroTag(item.mid);
final theme = Theme.of(context);
final style = TextStyle(
fontSize: theme.textTheme.labelSmall!.fontSize,
color: theme.colorScheme.outline,
);
return InkWell(
onTap: () => Get.toNamed(
'/member?mid=${item.mid}',

View File

@@ -151,6 +151,7 @@ class SearchVideoController
),
builder: (context) => StatefulBuilder(
builder: (context, setState) {
final theme = Theme.of(context);
Widget dateWidget([bool isFirst = true]) {
return SearchText(
text: DateFormat('yyyy-MM-dd')
@@ -200,12 +201,12 @@ class SearchVideoController
},
bgColor: currentPubTimeFilter == -1 &&
(isFirst ? customPubBeginDate : customPubEndDate)
? Theme.of(context).colorScheme.secondaryContainer
: Theme.of(context).colorScheme.outline.withOpacity(0.1),
? theme.colorScheme.secondaryContainer
: theme.colorScheme.outline.withOpacity(0.1),
textColor: currentPubTimeFilter == -1 &&
(isFirst ? customPubBeginDate : customPubEndDate)
? Theme.of(context).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.outline.withOpacity(0.8),
? theme.colorScheme.onSecondaryContainer
: theme.colorScheme.outline.withOpacity(0.8),
);
}
@@ -271,14 +272,10 @@ class SearchVideoController
SmartDialog.dismiss();
},
bgColor: item['value'] == currentPubTimeFilter
? Theme.of(context)
.colorScheme
.secondaryContainer
? theme.colorScheme.secondaryContainer
: null,
textColor: item['value'] == currentPubTimeFilter
? Theme.of(context)
.colorScheme
.onSecondaryContainer
? theme.colorScheme.onSecondaryContainer
: null,
),
)
@@ -318,14 +315,10 @@ class SearchVideoController
SmartDialog.dismiss();
},
bgColor: item['value'] == currentTimeFilter
? Theme.of(context)
.colorScheme
.secondaryContainer
? theme.colorScheme.secondaryContainer
: null,
textColor: item['value'] == currentTimeFilter
? Theme.of(context)
.colorScheme
.onSecondaryContainer
? theme.colorScheme.onSecondaryContainer
: null,
),
)
@@ -352,14 +345,10 @@ class SearchVideoController
SmartDialog.dismiss();
},
bgColor: item['value'] == currentZoneFilter
? Theme.of(context)
.colorScheme
.secondaryContainer
? theme.colorScheme.secondaryContainer
: null,
textColor: item['value'] == currentZoneFilter
? Theme.of(context)
.colorScheme
.onSecondaryContainer
? theme.colorScheme.onSecondaryContainer
: null,
),
)

View File

@@ -1,6 +1,5 @@
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
import 'package:PiliPlus/common/widgets/video_card_h.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/search/result.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
import 'package:PiliPlus/pages/search_panel/video/controller.dart';
@@ -16,7 +15,6 @@ class SearchVideoPanel extends CommonSearchPanel {
required super.keyword,
required super.tag,
required super.searchType,
super.hasHeader = true,
});
@override
@@ -36,95 +34,93 @@ class _SearchVideoPanelState extends CommonSearchPanelState<SearchVideoPanel,
);
@override
Widget buildHeader(LoadingState<List<SearchVideoItemModel>?> loadingState) {
if (loadingState is Success) {
return SliverPersistentHeader(
pinned: false,
floating: true,
delegate: CustomSliverPersistentHeaderDelegate(
extent: 34,
bgColor: Theme.of(context).colorScheme.surface,
child: Container(
height: 34,
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Wrap(
children: [
for (var i in controller.filterList) ...[
Obx(
() => SearchText(
fontSize: 13,
text: i['label'],
bgColor: Colors.transparent,
textColor:
controller.selectedType.value == i['type']
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
onTap: (value) async {
controller.selectedType.value = i['type'];
controller.order.value =
i['type'].toString().split('.').last;
SmartDialog.showLoading(msg: 'loading');
await controller.onReload();
SmartDialog.dismiss();
},
Widget buildList(ThemeData theme, List<SearchVideoItemModel> list) {
return SliverMainAxisGroup(
slivers: [
SliverPersistentHeader(
pinned: false,
floating: true,
delegate: CustomSliverPersistentHeaderDelegate(
extent: 34,
bgColor: theme.colorScheme.surface,
child: Container(
height: 34,
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Wrap(
children: [
for (var i in controller.filterList) ...[
Obx(
() => SearchText(
fontSize: 13,
text: i['label'],
bgColor: Colors.transparent,
textColor:
controller.selectedType.value == i['type']
? theme.colorScheme.primary
: theme.colorScheme.outline,
onTap: (value) async {
controller.selectedType.value = i['type'];
controller.order.value =
i['type'].toString().split('.').last;
SmartDialog.showLoading(msg: 'loading');
await controller.onReload();
SmartDialog.dismiss();
},
),
),
),
]
],
]
],
),
),
),
),
const VerticalDivider(indent: 7, endIndent: 8),
const SizedBox(width: 3),
SizedBox(
width: 32,
height: 32,
child: IconButton(
tooltip: '筛选',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () => controller.onShowFilterDialog(context),
icon: Icon(
Icons.filter_list_outlined,
size: 18,
color: Theme.of(context).colorScheme.primary,
const VerticalDivider(indent: 7, endIndent: 8),
const SizedBox(width: 3),
SizedBox(
width: 32,
height: 32,
child: IconButton(
tooltip: '筛选',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () => controller.onShowFilterDialog(context),
icon: Icon(
Icons.filter_list_outlined,
size: 18,
color: theme.colorScheme.primary,
),
),
),
),
],
],
),
),
),
),
);
}
return const SliverToBoxAdapter();
}
@override
Widget buildList(List<SearchVideoItemModel> list) {
return SliverPadding(
padding: const EdgeInsets.only(bottom: 80),
sliver: SliverGrid(
gridDelegate: Grid.videoCardHDelegate(context),
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == list.length - 1) {
controller.onLoadMore();
}
return VideoCardH(
videoItem: list[index],
showPubdate: true,
);
},
childCount: list.length,
SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom + 80),
sliver: SliverGrid(
gridDelegate: Grid.videoCardHDelegate(context),
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == list.length - 1) {
controller.onLoadMore();
}
return VideoCardH(
videoItem: list[index],
showPubdate: true,
);
},
childCount: list.length,
),
),
),
),
],
);
}
}

View File

@@ -20,13 +20,11 @@ abstract class CommonSearchPanel extends StatefulWidget {
required this.keyword,
required this.searchType,
required this.tag,
this.hasHeader = false,
});
final String keyword;
final SearchType searchType;
final String tag;
final bool hasHeader;
}
abstract class CommonSearchPanelState<
@@ -41,6 +39,7 @@ abstract class CommonSearchPanelState<
@override
Widget build(BuildContext context) {
super.build(context);
final theme = Theme.of(context);
return refreshIndicator(
onRefresh: () async {
await controller.onRefresh();
@@ -49,18 +48,12 @@ abstract class CommonSearchPanelState<
controller: controller.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
if (widget.hasHeader)
Obx(() => buildHeader(controller.loadingState.value)),
Obx(() => _buildBody(controller.loadingState.value)),
Obx(() => _buildBody(theme, controller.loadingState.value)),
],
),
);
}
Widget buildHeader(LoadingState<List<T>?> loadingState) {
throw UnimplementedError();
}
Widget get _builLoading {
return SliverGrid(
gridDelegate: switch (widget.searchType) {
@@ -103,7 +96,7 @@ abstract class CommonSearchPanelState<
);
}
Widget _buildBody(LoadingState<List<T>?> loadingState) {
Widget _buildBody(ThemeData theme, LoadingState<List<T>?> loadingState) {
return switch (loadingState) {
Loading() => widget.searchType == SearchType.live_room
? SliverPadding(
@@ -115,7 +108,7 @@ abstract class CommonSearchPanelState<
)
: _builLoading,
Success() => loadingState.response?.isNotEmpty == true
? buildList(loadingState.response!)
? buildList(theme, loadingState.response!)
: HttpError(
onReload: controller.onReload,
),
@@ -126,5 +119,5 @@ abstract class CommonSearchPanelState<
};
}
Widget buildList(List<T> list);
Widget buildList(ThemeData theme, List<T> list);
}