fix(recommend): 修正进度拖动与底栏联动

This commit is contained in:
Zhou Weidong committed 2026-10-22 20:15:07 +08:00
1 parent afe7a49ef0
commit 2765343340
9 files changed
+79 -107

No files matched your search

@@ -22,6 +22,7 @@ const double _progressHitHeight = 28;
const double _pageHorizontal = 14;
const double _railRight = 8;
const double _railGap = 12;
const double _bottomInfoInset = 20;
const double _railBottomOffset = 60;
const List<Shadow> _boostTextShadows = [
Shadow(color: AppColors.shadow, blurRadius: 5, offset: Offset(0, 1)),
@@ -141,7 +142,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
Positioned(
left: _pageHorizontal,
right: _railRight,
bottom: 12,
bottom: _bottomInfoInset,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
@@ -184,6 +185,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
void _endScrub() {
final wasVisible = _wasVisibleBeforeScrub;
if (_scrubbing) setState(() => _scrubbing = false);
widget.onScrubVisibilityChanged?.call(false);
widget.onScrubEnd?.call(wasVisible);
}
@@ -43,6 +43,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
double? _preview;
Timer? _bufferTimer;
bool _buffering = false;
bool _dragging = false;
@override
void initState() {
@@ -61,6 +62,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
_attachSource();
}
if (oldWidget.cancelScrubRequest != widget.cancelScrubRequest) {
_dragging = false;
_preview = null;
}
if (oldWidget.locked != widget.locked) {
@@ -68,6 +70,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
_bufferTimer = null;
_buffering = false;
if (widget.locked) {
_dragging = false;
_preview = null;
} else {
_syncBufferState(notify: false);
@@ -88,7 +91,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
builder: (context, constraints) {
final width = constraints.maxWidth;
final source = widget.controller;
final scrubbing = _preview != null;
final scrubbing = _dragging;
final loading = !widget.locked && !scrubbing && _buffering;
final track = widget.locked
? _inactiveTrack()
@@ -115,49 +118,41 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
!loading &&
(source?.value.isInitialized ?? false);
final video = source?.value;
final previewPosition = _preview == null || video == null
final previewPosition = !_dragging || _preview == null || video == null
? null
: seekPositionForFraction(_preview!, video.duration);
final showPreview = previewPosition != null;
return GestureDetector(
key: const Key('home-feed-progress'),
return Listener(
behavior: HitTestBehavior.opaque,
onHorizontalDragStart: interactive
? (details) {
widget.onScrubStart?.call();
_update(details.localPosition.dx / width);
}
: null,
onHorizontalDragUpdate: interactive
? (details) => _update(details.localPosition.dx / width)
: null,
onHorizontalDragEnd: interactive
? (_) {
widget.onScrubEnd?.call();
_commit(_preview);
}
: null,
onHorizontalDragCancel: interactive
? () {
widget.onScrubEnd?.call();
_cancelPreview();
}
: null,
child: Stack(
clipBehavior: Clip.none,
children: [
track,
if (showPreview)
Positioned(
left: _timeBubbleLeft(width, _preview!),
bottom: _lineCenterFromBottom + 16,
child: _ScrubTimeBubble(
key: const Key('scrub-preview-time-bubble'),
position: previewPosition,
duration: video!.duration,
onPointerUp: (_) => _finishScrub(),
onPointerCancel: (_) => _finishScrub(),
child: GestureDetector(
key: const Key('home-feed-progress'),
behavior: HitTestBehavior.opaque,
onHorizontalDragStart: interactive
? (details) => _startScrub(details.localPosition.dx / width)
: null,
onHorizontalDragUpdate: interactive
? (details) => _update(details.localPosition.dx / width)
: null,
onHorizontalDragEnd: interactive ? (_) => _finishScrub() : null,
onHorizontalDragCancel: interactive ? _finishScrub : null,
child: Stack(
clipBehavior: Clip.none,
children: [
track,
if (showPreview)
Positioned(
left: _timeBubbleLeft(width, _preview!),
bottom: _lineCenterFromBottom + 16,
child: _ScrubTimeBubble(
key: const Key('scrub-preview-time-bubble'),
position: previewPosition,
duration: video!.duration,
),
),
),
],
],
),
),
);
},
@@ -259,23 +254,32 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
);
}
void _startScrub(double fraction) {
if (_dragging) return;
setState(() {
_dragging = true;
_preview = fraction.clamp(0.0, 1.0).toDouble();
});
widget.onScrubStart?.call();
}
void _update(double fraction) {
if (!_dragging) return;
setState(() => _preview = fraction.clamp(0.0, 1.0).toDouble());
}
void _commit(double? fraction) {
void _finishScrub() {
if (!_dragging) return;
final fraction = _preview;
setState(() {
_dragging = false;
_preview = null;
});
widget.onScrubEnd?.call();
if (widget.locked || fraction == null) return;
final total = widget.controller?.value.duration.inMilliseconds ?? 0;
if (total > 0) {
widget.onSeek?.call(
Duration(milliseconds: (total * fraction.clamp(0.0, 1.0)).round()),
);
}
setState(() => _preview = null);
}
void _cancelPreview() {
setState(() => _preview = null);
if (total <= 0) return;
widget.onSeek?.call(Duration(milliseconds: (total * fraction).round()));
}
Widget _track(double fraction, double width) {