fix(home): 修正首页分类与卡片布局

This commit is contained in:
Zhou Weidong committed 2026-10-22 18:14:33 +08:00
1 parent 10477562d4
commit aa4870cce6
14 files changed
+573 -459

No files matched your search

@@ -36,6 +36,8 @@ class AllDramasFilterGrid extends StatefulWidget {
}
class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
String _region = 'all';
String _audio = 'all';
String? _genre;
bool _newest = false;
@@ -71,7 +73,11 @@ class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
icon: Icons.movie_filter_outlined,
title: l10n.homeGridFilterEmpty,
actionLabel: l10n.homeGridClearFilter,
onAction: () => setState(() => _genre = null),
onAction: () => setState(() {
_region = 'all';
_audio = 'all';
_genre = null;
}),
),
)
else
@@ -130,12 +136,28 @@ class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
child: Column(
key: const Key('all-dramas-filters'),
children: [
_chipRow(0, [l10n.all]),
_chipRow(1, [l10n.all]),
_chipRow(2, [
(id: null, label: l10n.all),
for (final genre in genres) (id: genre.id, label: genre.label),
]),
_selectableRow(
0,
[
(id: 'all', label: l10n.all),
(id: 'local', label: l10n.localFilter),
(id: 'asia', label: l10n.asiaFilter),
(id: 'western', label: l10n.westernFilter),
],
selected: _region,
onSelected: (value) => setState(() => _region = value),
),
_selectableRow(
1,
[
(id: 'all', label: l10n.all),
(id: 'subtitles', label: l10n.subtitlesOnlyFilter),
(id: 'dubbed', label: l10n.dubbedFilter),
],
selected: _audio,
onSelected: (value) => setState(() => _audio = value),
),
_genreRow(2, genres, l10n),
Row(
key: const Key('all-filter-row-3'),
children: [
@@ -173,7 +195,12 @@ class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
);
}
Widget _chipRow(int row, List<Object> options) {
Widget _selectableRow(
int row,
List<({String id, String label})> options, {
required String selected,
required ValueChanged<String> onSelected,
}) {
return Padding(
key: Key('all-filter-row-$row'),
padding: const EdgeInsets.only(bottom: AppDimens.spaceSm),
@@ -182,14 +209,12 @@ class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
child: Row(
children: [
for (final option in options) ...[
if (option is String)
_chip(label: option, selected: true, onTap: () {}),
if (option is ({String? id, String label}))
_chip(
label: option.label,
selected: _genre == option.id,
onTap: () => setState(() => _genre = option.id),
),
_chip(
key: Key('all-filter-${option.id}'),
label: option.label,
selected: selected == option.id,
onTap: () => onSelected(option.id),
),
const SizedBox(width: AppDimens.spaceSm),
],
],
@@ -198,6 +223,23 @@ class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
);
}
Widget _genreRow(
int row,
List<({String id, String label})> options,
AppLocalizations l10n,
) {
return _selectableRow(
row,
[
(id: 'all', label: l10n.all),
for (final genre in options) (id: genre.id, label: genre.label),
],
selected: _genre ?? 'all',
onSelected: (value) =>
setState(() => _genre = value == 'all' ? null : value),
);
}
Widget _chip({
Key? key,
required String label,
@@ -248,6 +290,7 @@ class _AllDramasFilterGridState extends State<AllDramasFilterGrid> {
}
List<Drama> _filtered() {
if (_region != 'all' || _audio != 'all') return const [];
final dramas = widget.feedController.dramas
.where((drama) {
return _genre == null || _matchesGenre(drama, _genre!, const []);
@@ -35,6 +35,7 @@ class RecommendSectionCard extends StatelessWidget {
onTap: onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ClipRRect(
@@ -83,6 +84,8 @@ class RecommendSectionCard extends StatelessWidget {
const SizedBox(height: AppDimens.cardCoverTitleGap),
Row(
key: Key('recommend-views-$sectionKey-${drama.id}'),
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Icon(
Icons.play_arrow_rounded,
@@ -123,38 +126,16 @@ class RecommendSectionCard extends StatelessWidget {
Widget _tags() {
final tags = _cardTags();
return Row(
children: [
for (final (index, tag) in tags.indexed)
Flexible(
child: Padding(
padding: EdgeInsets.only(
right: index == tags.length - 1 ? 0 : AppDimens.spaceXs,
),
child: Container(
key: Key('recommend-tag-$sectionKey-${drama.id}-$index'),
height: AppDimens.cardTagHeight,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(
horizontal: AppDimens.cardTagHorizontalPadding,
),
decoration: BoxDecoration(
color: AppColors.contentSurface,
borderRadius: BorderRadius.circular(AppDimens.cardTagRadius),
),
child: Text(
tag,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.textTertiary,
fontSize: AppDimens.cardTagFont,
),
),
),
),
),
],
return Text(
tags.join(' | '),
key: Key('recommend-tags-$sectionKey-${drama.id}'),
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: const TextStyle(
color: AppColors.textTertiary,
fontSize: AppDimens.cardTagFont,
),
);
}
@@ -164,7 +145,7 @@ class RecommendSectionCard extends StatelessWidget {
.expand((value) => value.split(_tagSplitter))
.map((value) => value.trim())
.where((value) => value.isNotEmpty && seen.add(value))
.take(2)
.take(3)
.toList(growable: false);
}
}