fix(recommend): 修正热播信息行与操作栏位置

This commit is contained in:
Zhou Weidong committed 2026-10-22 19:46:44 +08:00
1 parent 8737937875
commit 0c06a6dccd
11 files changed
+78 -5

No files matched your search

+2
View File
@@ -1175,3 +1175,5 @@ $ flutter test
- 右侧保留收藏/点赞/选集,白色 32 图标、28 间距;评论、分享入口已从该浮层移除。 - 右侧保留收藏/点赞/选集,白色 32 图标、28 间距;评论、分享入口已从该浮层移除。
- 底部信息重构为标题、真实热度、剧名、题材/集数、可展开简介与渐变观看全集按钮。 - 底部信息重构为标题、真实热度、剧名、题材/集数、可展开简介与渐变观看全集按钮。
- 新增三语“观看全集”文案;按当前流程未执行 analyze/test。 - 新增三语“观看全集”文案;按当前流程未执行 analyze/test。
- 榜单行支持可选排名:有名次显示 `TOPn·热播榜`,无名次回退“热播榜”;热度值改用 `w` 格式。
- 题材改为空格分隔,集数固定右侧单行;右侧操作栏改为距屏幕边缘 8,底部位置不变。
+3
View File
@@ -749,5 +749,8 @@
"watchedToEpisode": "Watched to Episode {episode}", "watchedToEpisode": "Watched to Episode {episode}",
"@watchedToEpisode": { "placeholders": { "episode": { "type": "int" } } }, "@watchedToEpisode": { "placeholders": { "episode": { "type": "int" } } },
"homeWatchAll": "Watch all", "homeWatchAll": "Watch all",
"hotChartLabel": "Trending",
"hotChartRanked": "TOP{rank} · Trending",
"@hotChartRanked": { "placeholders": { "rank": { "type": "int" } } },
"confirmRemove": "Remove this item?" "confirmRemove": "Remove this item?"
} }
+3
View File
@@ -706,5 +706,8 @@
"watchedToEpisode": "Ditonton hingga Episode {episode}", "watchedToEpisode": "Ditonton hingga Episode {episode}",
"@watchedToEpisode": { "placeholders": { "episode": { "type": "int" } } }, "@watchedToEpisode": { "placeholders": { "episode": { "type": "int" } } },
"homeWatchAll": "Tonton semua", "homeWatchAll": "Tonton semua",
"hotChartLabel": "Peringkat populer",
"hotChartRanked": "TOP{rank} · Populer",
"@hotChartRanked": { "placeholders": { "rank": { "type": "int" } } },
"confirmRemove": "Hapus item ini?" "confirmRemove": "Hapus item ini?"
} }
+12
View File
@@ -3262,6 +3262,18 @@ abstract class AppLocalizations {
/// **'Watch all'** /// **'Watch all'**
String get homeWatchAll; String get homeWatchAll;
/// No description provided for @hotChartLabel.
///
/// In en, this message translates to:
/// **'Trending'**
String get hotChartLabel;
/// No description provided for @hotChartRanked.
///
/// In en, this message translates to:
/// **'TOP{rank} · Trending'**
String hotChartRanked(int rank);
/// No description provided for @confirmRemove. /// No description provided for @confirmRemove.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
+8
View File
@@ -1702,6 +1702,14 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get homeWatchAll => 'Watch all'; String get homeWatchAll => 'Watch all';
@override
String get hotChartLabel => 'Trending';
@override
String hotChartRanked(int rank) {
return 'TOP$rank · Trending';
}
@override @override
String get confirmRemove => 'Remove this item?'; String get confirmRemove => 'Remove this item?';
} }
+8
View File
@@ -1704,6 +1704,14 @@ class AppLocalizationsId extends AppLocalizations {
@override @override
String get homeWatchAll => 'Tonton semua'; String get homeWatchAll => 'Tonton semua';
@override
String get hotChartLabel => 'Peringkat populer';
@override
String hotChartRanked(int rank) {
return 'TOP$rank · Populer';
}
@override @override
String get confirmRemove => 'Hapus item ini?'; String get confirmRemove => 'Hapus item ini?';
} }
+8
View File
@@ -1678,6 +1678,14 @@ class AppLocalizationsZh extends AppLocalizations {
@override @override
String get homeWatchAll => '观看全集'; String get homeWatchAll => '观看全集';
@override
String get hotChartLabel => '热播榜';
@override
String hotChartRanked(int rank) {
return 'TOP$rank·热播榜';
}
@override @override
String get confirmRemove => '确定移除这条内容吗?'; String get confirmRemove => '确定移除这条内容吗?';
} }
+3
View File
@@ -668,5 +668,8 @@
"watchedToEpisode": "已看至 第 {episode} 集", "watchedToEpisode": "已看至 第 {episode} 集",
"@watchedToEpisode": { "placeholders": { "episode": { "type": "int" } } }, "@watchedToEpisode": { "placeholders": { "episode": { "type": "int" } } },
"homeWatchAll": "观看全集", "homeWatchAll": "观看全集",
"hotChartLabel": "热播榜",
"hotChartRanked": "TOP{rank}·热播榜",
"@hotChartRanked": { "placeholders": { "rank": { "type": "int" } } },
"confirmRemove": "确定移除这条内容吗?" "confirmRemove": "确定移除这条内容吗?"
} }
@@ -21,6 +21,7 @@ part 'home_feed_overlay_parts.dart';
const double _progressHeight = 2; const double _progressHeight = 2;
const double _progressHitHeight = 12; const double _progressHitHeight = 12;
const double _pageHorizontal = 14; const double _pageHorizontal = 14;
const double _railRight = 8;
const double _railGap = 12; const double _railGap = 12;
const double _railBottomOffset = 60; const double _railBottomOffset = 60;
const List<Shadow> _boostTextShadows = [ const List<Shadow> _boostTextShadows = [
@@ -53,6 +54,7 @@ class HomeFeedOverlay extends StatefulWidget {
required this.onMore, required this.onMore,
this.likeCount, this.likeCount,
this.favoriteCount, this.favoriteCount,
this.rankingRank,
this.commentCount, this.commentCount,
this.authorNote = '', this.authorNote = '',
this.onScrubStart, this.onScrubStart,
@@ -69,6 +71,7 @@ class HomeFeedOverlay extends StatefulWidget {
final bool liked; final bool liked;
final int? likeCount; final int? likeCount;
final int? favoriteCount; final int? favoriteCount;
final int? rankingRank;
final int? commentCount; final int? commentCount;
final bool saved; final bool saved;
final String authorNote; final String authorNote;
@@ -123,7 +126,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
else if (widget.visible) else if (widget.visible)
Positioned( Positioned(
left: _pageHorizontal, left: _pageHorizontal,
right: _pageHorizontal, right: _railRight,
bottom: 12, bottom: 12,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
@@ -200,6 +203,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
Widget _rail() { Widget _rail() {
return HomeFeedActionRail( return HomeFeedActionRail(
key: const Key('home-feed-action-rail'),
saved: widget.saved, saved: widget.saved,
liked: widget.liked, liked: widget.liked,
favoriteCount: widget.favoriteCount, favoriteCount: widget.favoriteCount,
@@ -216,6 +220,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
episode: widget.episode, episode: widget.episode,
onDetail: widget.onDetail, onDetail: widget.onDetail,
onOpenFullPlayer: widget.onOpenFullPlayer, onOpenFullPlayer: widget.onOpenFullPlayer,
rankingRank: widget.rankingRank,
); );
} }
} }
@@ -30,12 +30,14 @@ class HomeFeedInfoPanel extends StatefulWidget {
required this.episode, required this.episode,
required this.onDetail, required this.onDetail,
required this.onOpenFullPlayer, required this.onOpenFullPlayer,
this.rankingRank,
}); });
final Drama drama; final Drama drama;
final Episode episode; final Episode episode;
final VoidCallback onDetail; final VoidCallback onDetail;
final VoidCallback onOpenFullPlayer; final VoidCallback onOpenFullPlayer;
final int? rankingRank;
@override @override
State<HomeFeedInfoPanel> createState() => _HomeFeedInfoPanelState(); State<HomeFeedInfoPanel> createState() => _HomeFeedInfoPanelState();
@@ -119,6 +121,7 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
Widget _metaPills(AppLocalizations l10n) { Widget _metaPills(AppLocalizations l10n) {
final hot = isHotDrama(widget.drama); final hot = isHotDrama(widget.drama);
final views = widget.drama.viewCount; final views = widget.drama.viewCount;
final rank = widget.rankingRank;
if (!hot && views <= 0) return const SizedBox.shrink(); if (!hot && views <= 0) return const SizedBox.shrink();
return Wrap( return Wrap(
key: const Key('home-feed-meta-pills'), key: const Key('home-feed-meta-pills'),
@@ -139,7 +142,9 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
), ),
const SizedBox(width: 2), const SizedBox(width: 2),
Text( Text(
l10n.rankingHot, rank != null && rank > 0
? l10n.hotChartRanked(rank)
: l10n.hotChartLabel,
style: const TextStyle( style: const TextStyle(
color: AppColors.textPrimary, color: AppColors.textPrimary,
fontSize: _metaFont, fontSize: _metaFont,
@@ -154,7 +159,7 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
key: const Key('home-feed-view-pill'), key: const Key('home-feed-view-pill'),
background: AppColors.overlaySoft, background: AppColors.overlaySoft,
child: Text( child: Text(
formatInteractionCount(views), formatPlayCount(views),
style: const TextStyle( style: const TextStyle(
color: AppColors.textPrimary, color: AppColors.textPrimary,
fontSize: _metaFont, fontSize: _metaFont,
@@ -209,7 +214,7 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
], ],
Expanded( Expanded(
child: Text( child: Text(
genres.join(' | '), genres.join(' '),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle( style: const TextStyle(
@@ -225,6 +230,8 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
widget.drama.episodeCount, widget.drama.episodeCount,
), ),
key: const Key('home-feed-episode-progress'), key: const Key('home-feed-episode-progress'),
maxLines: 1,
softWrap: false,
style: const TextStyle( style: const TextStyle(
color: AppColors.overlaySecondary, color: AppColors.overlaySecondary,
fontSize: _metaFont, fontSize: _metaFont,
+15 -1
View File
@@ -371,9 +371,16 @@ void main() {
.data, .data,
'Episode 2 / 8 total', 'Episode 2 / 8 total',
); );
expect(find.textContaining('41.9万'), findsOneWidget); expect(find.textContaining('41.9w'), findsOneWidget);
expect(find.byKey(const Key('home-feed-ranking-pill')), findsOneWidget); expect(find.byKey(const Key('home-feed-ranking-pill')), findsOneWidget);
expect(find.byKey(const Key('home-feed-view-pill')), findsOneWidget); expect(find.byKey(const Key('home-feed-view-pill')), findsOneWidget);
expect(find.text('Trending'), findsOneWidget);
expect(find.text('Romance Urban'), findsOneWidget);
final episodeProgress = tester.widget<Text>(
find.byKey(const Key('home-feed-episode-progress')),
);
expect(episodeProgress.maxLines, 1);
expect(episodeProgress.softWrap, isFalse);
expect( expect(
tester.widget<Text>(find.byKey(const Key('rail-like-count'))).data, tester.widget<Text>(find.byKey(const Key('rail-like-count'))).data,
'1006', '1006',
@@ -407,6 +414,13 @@ void main() {
expect(find.byKey(const Key('rail-comments')), findsNothing); expect(find.byKey(const Key('rail-comments')), findsNothing);
expect(find.byKey(const Key('rail-share')), findsNothing); expect(find.byKey(const Key('rail-share')), findsNothing);
expect(find.text('Comments'), findsNothing); expect(find.text('Comments'), findsNothing);
expect(
tester.getRect(find.byKey(const Key('home-feed-action-rail'))).right,
closeTo(
tester.getRect(find.byKey(const Key('home-feed-gesture'))).right - 8,
0.1,
),
);
expect(find.byKey(const Key('progress-loading')), findsNothing); expect(find.byKey(const Key('progress-loading')), findsNothing);
expect( expect(
find.byKey(const Key('home-feed-progress-inactive')), find.byKey(const Key('home-feed-progress-inactive')),