fix(player): 优化加载指示器与锁定进度条

This commit is contained in:
Zhou Weidong committed 2026-10-22 10:09:33 +08:00
1 parent 7b068e8eb4
commit 623c184243
13 files changed
+393 -33

No files matched your search

@@ -9,6 +9,8 @@ import 'package:video_player/video_player.dart';
import '../../../core/theme/app_colors.dart';
import 'loading_progress_track.dart';
const Key _inactiveTrackKey = Key('progress-inactive');
/// Keeps seeks within the playable range so dragging to the edge does not
/// trigger the player's completion callback before playback resumes.
Duration seekPositionForFraction(double fraction, Duration duration) {
@@ -29,6 +31,7 @@ class SeekProgressBar extends StatefulWidget {
this.showTimes = true,
this.compact = false,
this.inactiveTrackColor = AppColors.border,
this.locked = false,
});
final ValueListenable<VideoPlayerValue>? valueListenable;
@@ -38,6 +41,7 @@ class SeekProgressBar extends StatefulWidget {
final bool showTimes;
final bool compact;
final Color inactiveTrackColor;
final bool locked;
@override
State<SeekProgressBar> createState() => _SeekProgressBarState();
@@ -67,6 +71,16 @@ class _SeekProgressBarState extends State<SeekProgressBar> {
_buffering = false;
_attachSource();
}
if (oldWidget.locked != widget.locked) {
_bufferTimer?.cancel();
_bufferTimer = null;
_buffering = false;
if (widget.locked) {
_previewFraction.value = null;
} else {
_syncBufferState(notify: false);
}
}
}
@override
@@ -90,7 +104,7 @@ class _SeekProgressBarState extends State<SeekProgressBar> {
void _syncBufferState({bool notify = true}) {
final source = widget.valueListenable;
if (source == null) {
if (widget.locked || source == null) {
_bufferTimer?.cancel();
_bufferTimer = null;
_setBuffering(false, notify: notify);
@@ -133,6 +147,7 @@ class _SeekProgressBarState extends State<SeekProgressBar> {
}
Future<void> _finish(double fraction, Duration duration) async {
if (widget.locked) return;
final source = widget.valueListenable;
_previewFraction.value = fraction;
try {
@@ -166,8 +181,13 @@ class _SeekProgressBarState extends State<SeekProgressBar> {
Widget _buildTrack(BuildContext context, VideoPlayerValue video) {
final total = video.duration.inMilliseconds;
final scrubbing = _previewFraction.value != null;
final loading = !scrubbing && (!video.isInitialized || _buffering);
final enabled = video.isInitialized && total > 0 && widget.onSeek != null;
final loading =
!widget.locked && !scrubbing && (!video.isInitialized || _buffering);
final enabled =
!widget.locked &&
video.isInitialized &&
total > 0 &&
widget.onSeek != null;
final played = total > 0
? (video.position.inMilliseconds / total).clamp(0.0, 1.0)
: 0.0;
@@ -203,7 +223,9 @@ class _SeekProgressBarState extends State<SeekProgressBar> {
),
SizedBox(
height: trackAreaHeight,
child: loading
child: widget.locked
? _inactiveTrack(trackHeight)
: loading
? Center(
child: LoadingProgressTrack(
height: trackHeight,
@@ -251,6 +273,19 @@ class _SeekProgressBarState extends State<SeekProgressBar> {
);
}
Widget _inactiveTrack(double height) {
return Center(
child: SizedBox(
width: double.infinity,
height: height,
child: ColoredBox(
key: _inactiveTrackKey,
color: widget.inactiveTrackColor,
),
),
);
}
String _format(Duration value) {
final minutes = value.inMinutes.remainder(60).toString().padLeft(2, '0');
final seconds = value.inSeconds.remainder(60).toString().padLeft(2, '0');