feat(flutter): 榜单前三铺满与剧场分类吸顶下划线

This commit is contained in:
Zhou Weidong committed 2026-10-20 15:13:12 +08:00
1 parent d80fff74ba
commit 04a1a4ee82
4 files changed
+130 -52

No files matched your search

+66 -34
View File
@@ -16,10 +16,6 @@ import '../drama_detail/drama_detail_view.dart';
const int _topCount = 50;
const double _podiumGap = 8;
const double _centerCoverWidth = 120;
const double _centerCoverHeight = 160;
const double _sideCoverWidth = 92;
const double _sideCoverHeight = 124;
const double _coverRadius = 12;
const double _titleSlotHeight = 24;
const double _rowGap = 12;
@@ -87,14 +83,13 @@ class _Podium extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(width: _sideCoverWidth, child: _slot(2)),
Expanded(flex: 100, child: _slot(2)),
const SizedBox(width: _podiumGap),
SizedBox(width: _centerCoverWidth, child: _slot(1)),
Expanded(flex: 115, child: _slot(1)),
const SizedBox(width: _podiumGap),
SizedBox(width: _sideCoverWidth, child: _slot(3)),
Expanded(flex: 100, child: _slot(3)),
],
);
}
@@ -118,9 +113,6 @@ class _PodiumCard extends StatelessWidget {
bool get _center => rank == 1;
double get _width => _center ? _centerCoverWidth : _sideCoverWidth;
double get _height => _center ? _centerCoverHeight : _sideCoverHeight;
LinearGradient get _badgeGradient => switch (rank) {
1 => const LinearGradient(
begin: Alignment.topLeft,
@@ -150,10 +142,9 @@ class _PodiumCard extends StatelessWidget {
children: [
ClipRRect(
borderRadius: BorderRadius.circular(_coverRadius),
child: SizedBox(
child: AspectRatio(
key: Key('ranking-cover-$rank'),
width: _width,
height: _height,
aspectRatio: 3 / 4,
child: Stack(
fit: StackFit.expand,
children: [
@@ -228,9 +219,21 @@ class _RankingRow extends StatelessWidget {
int get _rank => index + 1;
List<String> _tagValues() {
final result = <String>[];
for (final value in [drama.genre, drama.category]) {
for (final part in value.split(RegExp(r'[,/、·]'))) {
final tag = part.trim();
if (tag.isEmpty || result.contains(tag)) continue;
result.add(tag);
if (result.length == 3) return result;
}
}
return result;
}
@override
Widget build(BuildContext context) {
final genre = drama.genre.isEmpty ? drama.category : drama.genre;
return Container(
decoration: BoxDecoration(
color: AppColors.card,
@@ -293,26 +296,46 @@ class _RankingRow extends StatelessWidget {
fontWeight: FontWeight.w700,
),
),
if (genre.isNotEmpty) ...[
if (drama.synopsis.trim().isNotEmpty) ...[
const SizedBox(height: 4),
Text(
drama.synopsis,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.muted,
fontSize: 12,
height: 1.3,
),
),
],
if (_tagValues().isNotEmpty) ...[
const SizedBox(height: 6),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: AppColors.raised,
borderRadius: BorderRadius.circular(6),
),
child: Text(
genre,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.muted,
fontSize: 11,
),
),
Wrap(
spacing: 6,
runSpacing: 4,
children: [
for (final tag in _tagValues())
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: AppColors.raised,
borderRadius: BorderRadius.circular(6),
),
child: Text(
tag,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.muted,
fontSize: 11,
),
),
),
],
),
],
const SizedBox(height: 8),
@@ -337,6 +360,15 @@ class _RankingRow extends StatelessWidget {
),
),
),
const SizedBox(width: 8),
Text(
l10n.episodeCount(drama.episodeCount),
maxLines: 1,
style: const TextStyle(
color: AppColors.muted,
fontSize: 11,
),
),
],
),
],