fix(recommend): 更正筛选按钮所属页面

This commit is contained in:
Zhou Weidong committed 2026-10-22 21:05:51 +08:00
1 parent bf20e44b85
commit 13d70fcef2
10 files changed
+124 -107

No files matched your search

+1
View File
@@ -1228,3 +1228,4 @@ $ flutter test
- 首页二级标签行改为纯横向滑动,右侧三横线按钮不渲染也不占位。
- 删除不再使用的筛选回调、尺寸 token、颜色和 CustomPainter;全部短剧页筛选按钮保持不变。
- `flutter analyze`:No issues found。
- 按后续更正恢复首页透明三横线按钮(26、无背景、`#7A7A7E`),删除全部短剧第 4 行圆形按钮及回调链路。
+1 -2
View File
@@ -80,8 +80,6 @@ abstract final class AppColors {
static const filterChipSelected = Color(0xFF21090E);
static const filterChipTextSelected = Color(0xFFFF4D6A);
static const filterChipTextInactive = Color(0xFF8A8A8A);
static const filterMenuButton = Color(0xFF2A2A2A);
static const filterMenuIcon = Color(0xFFBDBDBD);
/// 「我的」页卡片与描边。
static const mineCard = Color(0xFF16161A);
@@ -92,6 +90,7 @@ abstract final class AppColors {
static const textSecondary = Color(0xFF8E8E93);
static const textTertiary = Color(0xFF9E9E9E);
static const textTabInactive = Color(0xFFB0B0B0);
static const textFilterIcon = Color(0xFF7A7A7E);
/// 原生开屏与冷启动过渡底色。
static const splashInk = ink;
+4 -3
View File
@@ -114,6 +114,10 @@ abstract final class AppDimens {
static const Duration homeSecondaryTagAnimationDuration = Duration(
milliseconds: 150,
);
static const double homeSecondaryFilterGap = 6;
static const double homeSecondaryFilterVisualSize = 26;
static const double homeSecondaryFilterIcon = 16;
static const double homeSecondaryFilterStroke = 1.7;
static const double homePrimaryCategoryGap = 24;
static const double homeSecondaryTagGap = 10;
static const double homeSearchTopGap = 0;
@@ -143,9 +147,6 @@ abstract final class AppDimens {
static const double allDramasGridGap = 6;
static const double allDramasGridRowGap = 12;
static const double allDramasFilterToGridGap = 12;
static const double allDramasFilterIcon = 22;
static const double allDramasFilterButton = 44;
static const double allDramasFilterRight = 12;
static const double followingTabFont = 16;
static const double followingGridAspectRatio = 0.5;
+1 -1
View File
@@ -276,6 +276,7 @@ class _HomeTabsState extends State<_HomeTabs> {
onSearch: () => _openSearch(context),
onOpenVip: () => unawaited(_openVip(context)),
onOpenWallet: () => unawaited(_openWallet(context)),
onOpenFilter: () => _pushPage(context, const FilterPage()),
),
onOpenDrama: (drama) => unawaited(logic.playDrama(context, drama)),
);
@@ -286,7 +287,6 @@ class _HomeTabsState extends State<_HomeTabs> {
feedController: widget.feedController,
active: logic.tab == 1,
onSearch: () => _openSearch(context),
onOpenFilter: () => _pushPage(context, const FilterPage()),
);
}
+74 -15
View File
@@ -40,11 +40,13 @@ class HomeGridCallbacks {
required this.onSearch,
required this.onOpenVip,
required this.onOpenWallet,
required this.onOpenFilter,
});
final VoidCallback onSearch;
final VoidCallback onOpenVip;
final VoidCallback onOpenWallet;
final VoidCallback onOpenFilter;
}
class HomeGridHeader extends StatelessWidget {
@@ -80,7 +82,7 @@ class HomeGridHeader extends StatelessWidget {
_searchRow(l10n),
_primaryRow(l10n),
if (selectedPrimary == HomePrimaryTab.featured)
_tagRow()
_tagRow(l10n)
else
const SizedBox(height: AppDimens.homeSecondaryGridGap),
],
@@ -322,7 +324,7 @@ class HomeGridHeader extends StatelessWidget {
);
}
Widget _tagRow() {
Widget _tagRow(AppLocalizations l10n) {
return Padding(
padding: const EdgeInsets.fromLTRB(
AppDimens.feedPageHorizontal,
@@ -330,19 +332,54 @@ class HomeGridHeader extends StatelessWidget {
AppDimens.feedPageHorizontal,
AppDimens.homeSecondaryGridGap,
),
child: SingleChildScrollView(
key: const Key('home-secondary-tags'),
scrollDirection: Axis.horizontal,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
for (final tag in tags) ...[
_tagChip(tag),
const SizedBox(width: AppDimens.homeSecondaryTagGap),
],
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: SingleChildScrollView(
key: const Key('home-secondary-tags'),
scrollDirection: Axis.horizontal,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
for (final tag in tags) ...[
_tagChip(tag),
const SizedBox(width: AppDimens.homeSecondaryTagGap),
],
],
),
),
),
const SizedBox(width: AppDimens.homeSecondaryFilterGap),
Tooltip(
message: l10n.filter,
child: SizedBox.square(
dimension: AppDimens.homeSecondaryFilterVisualSize,
child: Material(
color: AppColors.transparent,
child: InkWell(
key: const Key('home-grid-filter'),
onTap: callbacks.onOpenFilter,
child: Center(
child: SizedBox.square(
key: const Key('home-secondary-filter-visual'),
dimension: AppDimens.homeSecondaryFilterVisualSize,
child: const Center(
child: CustomPaint(
key: Key('home-secondary-filter-icon'),
size: Size.square(AppDimens.homeSecondaryFilterIcon),
painter: _ThreeLineFilterPainter(),
),
),
),
),
),
),
),
),
],
),
);
}
@@ -380,3 +417,25 @@ class HomeGridHeader extends StatelessWidget {
);
}
}
class _ThreeLineFilterPainter extends CustomPainter {
const _ThreeLineFilterPainter();
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = AppColors.textFilterIcon
..strokeWidth = AppDimens.homeSecondaryFilterStroke
..strokeCap = StrokeCap.butt;
for (final y in [
size.height * 0.25,
size.height * 0.5,
size.height * 0.75,
]) {
canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
}
}
@override
bool shouldRepaint(_ThreeLineFilterPainter oldDelegate) => false;
}
-3
View File
@@ -24,13 +24,11 @@ class RecommendPage extends StatefulWidget {
required this.feedController,
required this.active,
required this.onSearch,
required this.onOpenFilter,
});
final HomeFeedController feedController;
final bool active;
final VoidCallback onSearch;
final VoidCallback onOpenFilter;
@override
State<RecommendPage> createState() => _RecommendPageState();
@@ -85,7 +83,6 @@ class _RecommendPageState extends State<RecommendPage> {
AllDramasFilterGrid(
feedController: widget.feedController,
onOpenDrama: _openDrama,
onOpenFilter: widget.onOpenFilter,
),
),
),
@@ -24,12 +24,10 @@ class AllDramasFilterGrid extends StatefulWidget {
super.key,
required this.feedController,
required this.onOpenDrama,
required this.onOpenFilter,
});
final HomeFeedController feedController;
final ValueChanged<Drama> onOpenDrama;
final VoidCallback onOpenFilter;
@override
State<AllDramasFilterGrid> createState() => _AllDramasFilterGridState();
@@ -295,49 +293,21 @@ class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
Widget _sortRow(AppLocalizations l10n) {
return _filterRow(
row: 3,
height: AppDimens.allDramasFilterButton,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: _horizontalChipScroll(
scrollKey: const Key('all-filter-scroll-3'),
chips: [
_chip(
key: const Key('all-sort-hot'),
label: l10n.hot,
selected: !_newest,
onTap: () => setState(() => _newest = false),
),
const SizedBox(width: AppDimens.filterItemGap),
_chip(
key: const Key('all-sort-new'),
label: l10n.newest,
selected: _newest,
onTap: () => setState(() => _newest = true),
),
],
),
child: _horizontalChipScroll(
scrollKey: const Key('all-filter-scroll-3'),
chips: [
_chip(
key: const Key('all-sort-hot'),
label: l10n.hot,
selected: !_newest,
onTap: () => setState(() => _newest = false),
),
const SizedBox(width: AppDimens.filterItemGap),
Material(
key: const Key('all-dramas-filter-page-button'),
color: AppColors.filterMenuButton,
shape: const CircleBorder(),
child: InkWell(
key: const Key('all-dramas-filter-page'),
customBorder: const CircleBorder(),
onTap: widget.onOpenFilter,
child: const SizedBox.square(
dimension: AppDimens.allDramasFilterButton,
child: Icon(
Icons.filter_list_rounded,
size: AppDimens.allDramasFilterIcon,
color: AppColors.filterMenuIcon,
),
),
),
_chip(
key: const Key('all-sort-new'),
label: l10n.newest,
selected: _newest,
onTap: () => setState(() => _newest = true),
),
],
),
+28 -6
View File
@@ -94,21 +94,43 @@ void main() {
expect(find.byKey(const Key('home-section-category-古装')), findsOneWidget);
expect(find.byKey(const Key('home-section-category-社群')), findsOneWidget);
expect(find.byKey(const Key('home-secondary-tags')), findsOneWidget);
expect(find.byKey(const Key('home-grid-filter')), findsOneWidget);
expect(
tester.getRect(find.byKey(const Key('home-secondary-tags'))).left,
closeTo(AppDimens.feedPageHorizontal, 0.1),
tester.getSize(find.byKey(const Key('home-grid-filter'))),
const Size.square(AppDimens.homeSecondaryFilterVisualSize),
);
expect(
tester.getRect(find.byKey(const Key('home-secondary-tags'))).right,
tester.getSize(find.byKey(const Key('home-secondary-filter-visual'))),
const Size.square(AppDimens.homeSecondaryFilterVisualSize),
);
expect(
tester.getCenter(find.byKey(const Key('home-grid-filter'))).dy,
closeTo(tester.getCenter(find.byKey(const Key('home-tag-hot'))).dy, 0.1),
);
expect(
tester.getRect(find.byKey(const Key('home-grid-filter'))).right,
closeTo(
tester.getRect(find.byKey(const Key('home-grid'))).right -
AppDimens.feedPageHorizontal,
0.1,
),
);
expect(find.byKey(const Key('home-grid-filter')), findsNothing);
expect(find.byKey(const Key('home-secondary-filter-visual')), findsNothing);
expect(find.byKey(const Key('home-secondary-filter-icon')), findsNothing);
final filterIcon = tester.widget<CustomPaint>(
find.byKey(const Key('home-secondary-filter-icon')),
);
expect(
filterIcon.size,
const Size.square(AppDimens.homeSecondaryFilterIcon),
);
final filterMaterial = tester.widget<Material>(
find
.ancestor(
of: find.byKey(const Key('home-grid-filter')),
matching: find.byType(Material),
)
.first,
);
expect(filterMaterial.color, AppColors.transparent);
final searchBox = find.descendant(
of: find.byKey(const Key('home-search-entry')),
matching: find.byType(Container),
@@ -25,7 +25,6 @@ void main() {
body: AllDramasFilterGrid(
feedController: controller,
onOpenDrama: (_) {},
onOpenFilter: () {},
),
),
),
+2 -33
View File
@@ -309,7 +309,7 @@ void main() {
}
expect(
tester.getSize(find.byKey(const Key('all-filter-row-3'))).height,
AppDimens.allDramasFilterButton,
AppDimens.filterChipHeight,
);
expect(
tester.getRect(find.byKey(const Key('all-dramas-scroll'))).top -
@@ -437,38 +437,7 @@ void main() {
(chipContainer.decoration! as BoxDecoration).borderRadius,
BorderRadius.circular(AppDimens.filterChipRadius),
);
final filterButton = find.byKey(const Key('all-dramas-filter-page'));
expect(
find.descendant(
of: find.byKey(const Key('all-filter-scroll-3')),
matching: filterButton,
),
findsNothing,
);
expect(
tester.getSize(filterButton),
const Size.square(AppDimens.allDramasFilterButton),
);
expect(
tester.getRect(filterButton).right,
closeTo(
tester.getRect(find.byKey(const Key('all-filter-row-3'))).right,
0.1,
),
);
final filterMaterial = tester.widget<Material>(
find.byKey(const Key('all-dramas-filter-page-button')),
);
expect(filterMaterial.color, AppColors.filterMenuButton);
expect(filterMaterial.shape, const CircleBorder());
final filterIcon = tester.widget<Icon>(
find.descendant(
of: filterButton,
matching: find.byIcon(Icons.filter_list_rounded),
),
);
expect(filterIcon.size, AppDimens.allDramasFilterIcon);
expect(filterIcon.color, AppColors.filterMenuIcon);
expect(find.byKey(const Key('all-dramas-filter-page')), findsNothing);
await tester.tap(find.byKey(const Key('recommend-tab-playlist')));
await tester.pumpAndSettle();