fix(recommend): 精简底部信息并优化进度拖动

This commit is contained in:
Zhou Weidong committed 2026-10-22 19:55:07 +08:00
1 parent ccda41b15b
commit d66ac8327e
16 files changed
+141 -163

No files matched your search

@@ -19,7 +19,7 @@ import 'seek_progress_bar.dart';
part 'home_feed_overlay_parts.dart';
const double _progressHeight = 2;
const double _progressHitHeight = 12;
const double _progressHitHeight = 24;
const double _pageHorizontal = 14;
const double _railRight = 8;
const double _railGap = 12;
@@ -54,10 +54,11 @@ class HomeFeedOverlay extends StatefulWidget {
required this.onMore,
this.likeCount,
this.favoriteCount,
this.rankingRank,
this.commentCount,
this.authorNote = '',
this.onScrubStart,
this.onScrubEnd,
this.onScrubVisibilityChanged,
this.onSeek,
this.thumbnailService,
this.spriteAxisService,
@@ -71,7 +72,6 @@ class HomeFeedOverlay extends StatefulWidget {
final bool liked;
final int? likeCount;
final int? favoriteCount;
final int? rankingRank;
final int? commentCount;
final bool saved;
final String authorNote;
@@ -89,6 +89,8 @@ class HomeFeedOverlay extends StatefulWidget {
final VoidCallback onBoostEnd;
final VoidCallback onMore;
final VoidCallback? onScrubStart;
final VoidCallback? onScrubEnd;
final ValueChanged<bool>? onScrubVisibilityChanged;
final ValueChanged<Duration>? onSeek;
final PlaybackThumbnailService? thumbnailService;
final SpriteThumbnailAxisService? spriteAxisService;
@@ -98,6 +100,8 @@ class HomeFeedOverlay extends StatefulWidget {
}
class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
bool _scrubbing = false;
@override
Widget build(BuildContext context) {
return SafeArea(
@@ -123,7 +127,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
),
if (widget.boosting)
Positioned(left: 0, right: 0, bottom: 20, child: _boostHint())
else if (widget.visible)
else if (widget.visible && !_scrubbing)
Positioned(
left: _pageHorizontal,
right: _railRight,
@@ -149,7 +153,8 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
locked: widget.locked,
height: _progressHeight,
hitHeight: _progressHitHeight,
onScrubStart: widget.onScrubStart,
onScrubStart: _startScrub,
onScrubEnd: _endScrub,
onSeek: widget.onSeek,
thumbnailService: widget.thumbnailService,
spriteAxisService: widget.spriteAxisService,
@@ -163,6 +168,18 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
);
}
void _startScrub() {
if (!_scrubbing) setState(() => _scrubbing = true);
widget.onScrubVisibilityChanged?.call(true);
widget.onScrubStart?.call();
}
void _endScrub() {
if (_scrubbing) setState(() => _scrubbing = false);
widget.onScrubVisibilityChanged?.call(false);
widget.onScrubEnd?.call();
}
void _handleLongPressStart(LongPressStartDetails details, double width) {
final third = width / 3;
final dx = details.localPosition.dx;
@@ -220,7 +237,6 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
episode: widget.episode,
onDetail: widget.onDetail,
onOpenFullPlayer: widget.onOpenFullPlayer,
rankingRank: widget.rankingRank,
);
}
}
@@ -16,6 +16,7 @@ class _FeedProgressBar extends StatefulWidget {
required this.height,
required this.hitHeight,
this.onScrubStart,
this.onScrubEnd,
this.onSeek,
this.thumbnailService,
this.spriteAxisService,
@@ -29,6 +30,7 @@ class _FeedProgressBar extends StatefulWidget {
final double height;
final double hitHeight;
final VoidCallback? onScrubStart;
final VoidCallback? onScrubEnd;
final ValueChanged<Duration>? onSeek;
final PlaybackThumbnailService? thumbnailService;
final SpriteThumbnailAxisService? spriteAxisService;
@@ -137,8 +139,18 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
onHorizontalDragUpdate: interactive
? (details) => _update(details.localPosition.dx / width)
: null,
onHorizontalDragEnd: interactive ? (_) => _commit(_preview) : null,
onHorizontalDragCancel: interactive ? _cancelPreview : null,
onHorizontalDragEnd: interactive
? (_) {
widget.onScrubEnd?.call();
_commit(_preview);
}
: null,
onHorizontalDragCancel: interactive
? () {
widget.onScrubEnd?.call();
_cancelPreview();
}
: null,
child: Stack(
clipBehavior: Clip.none,
children: [
@@ -10,9 +10,8 @@ import '../../../l10n/app_localizations.dart';
import '../../home/widgets/home_drama_classification.dart';
const double _headlineFont = 26;
const double _seriesFont = 17;
const double _metaFont = 12;
const double _tagFont = 12;
const double _seriesFont = 19;
const double _tagFont = 13;
const double _synopsisFont = 13;
const double _watchAllHeight = 44;
const double _actionGap = 28;
@@ -30,14 +29,12 @@ class HomeFeedInfoPanel extends StatefulWidget {
required this.episode,
required this.onDetail,
required this.onOpenFullPlayer,
this.rankingRank,
});
final Drama drama;
final Episode episode;
final VoidCallback onDetail;
final VoidCallback onOpenFullPlayer;
final int? rankingRank;
@override
State<HomeFeedInfoPanel> createState() => _HomeFeedInfoPanelState();
@@ -73,15 +70,14 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
),
),
const SizedBox(height: 8),
_metaPills(l10n),
if (_hasMeta()) const SizedBox(height: 8),
GestureDetector(
key: const Key('home-feed-series-name'),
behavior: HitTestBehavior.opaque,
onTap: widget.onDetail,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
Flexible(
child: Text(
dramaTitle,
maxLines: 1,
@@ -94,10 +90,11 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
),
),
),
const SizedBox(width: 4),
const Icon(
Icons.chevron_right_rounded,
size: 16,
color: AppColors.overlaySecondary,
size: 20,
color: AppColors.textPrimary,
),
],
),
@@ -114,81 +111,6 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
);
}
bool _hasMeta() {
return isHotDrama(widget.drama) || widget.drama.viewCount > 0;
}
Widget _metaPills(AppLocalizations l10n) {
final hot = isHotDrama(widget.drama);
final views = widget.drama.viewCount;
final rank = widget.rankingRank;
if (!hot && views <= 0) return const SizedBox.shrink();
return Wrap(
key: const Key('home-feed-meta-pills'),
spacing: 6,
runSpacing: 4,
children: [
if (hot)
_pill(
key: const Key('home-feed-ranking-pill'),
background: AppColors.error,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.local_fire_department_rounded,
size: 12,
color: AppColors.textPrimary,
),
const SizedBox(width: 2),
Text(
rank != null && rank > 0
? l10n.hotChartRanked(rank)
: l10n.hotChartLabel,
style: const TextStyle(
color: AppColors.textPrimary,
fontSize: _metaFont,
fontWeight: FontWeight.w600,
),
),
],
),
),
if (views > 0)
_pill(
key: const Key('home-feed-view-pill'),
background: AppColors.overlaySoft,
child: Text(
formatPlayCount(views),
style: const TextStyle(
color: AppColors.textPrimary,
fontSize: _metaFont,
fontWeight: FontWeight.w600,
),
),
),
],
);
}
Widget _pill({
required Key key,
required Color background,
required Widget child,
}) {
return Container(
key: key,
height: 22,
padding: const EdgeInsets.symmetric(horizontal: 8),
alignment: Alignment.center,
decoration: BoxDecoration(
color: background,
borderRadius: BorderRadius.circular(11),
),
child: child,
);
}
Widget _tagMetaRow(AppLocalizations l10n, List<String> genres) {
return Row(
key: const Key('home-feed-tags'),
@@ -210,20 +132,21 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
),
),
),
const SizedBox(width: 6),
const SizedBox(width: 8),
],
Expanded(
Flexible(
fit: FlexFit.loose,
child: Text(
genres.join(' '),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.overlaySecondary,
color: AppColors.overlayLabel,
fontSize: _tagFont,
),
),
),
const SizedBox(width: 6),
const SizedBox(width: 8),
Text(
l10n.favoriteEpisodeProgress(
widget.episode.number,
@@ -233,8 +156,8 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
maxLines: 1,
softWrap: false,
style: const TextStyle(
color: AppColors.overlaySecondary,
fontSize: _metaFont,
color: AppColors.overlayLabel,
fontSize: _tagFont,
),
),
],
@@ -298,7 +221,7 @@ class _HomeFeedInfoPanelState extends State<HomeFeedInfoPanel> {
bottom: 0,
child: _synopsisToggle(
key: const Key('home-feed-synopsis-more'),
label: l10n.more,
label: l10n.expandSynopsis,
),
),
],