refactor progress bar

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-06-26 12:45:41 +08:00
parent 2ba6f0d063
commit a623ceee47
12 changed files with 263 additions and 391 deletions

View File

@@ -72,38 +72,31 @@ class PlPlayerController with BlockConfigMixin {
Player? _videoPlayerController;
VideoController? _videoController;
// 添加一个私有静态变量来保存实例
static PlPlayerController? _instance;
// 流事件 监听播放状态变化
// StreamSubscription? _playerEventSubs;
final playerStatus = PlPlayerStatus(.playing);
/// [playerStatus] has a [status] observable
final playerStatus = PlPlayerStatus(PlayerStatus.playing);
final Rx<DataStatus> dataStatus = Rx(.none);
///
final Rx<DataStatus> dataStatus = Rx(DataStatus.none);
Duration? seekToPos;
bool hasToasted = false;
final RxBool isSeeking = false.obs;
// bool controlsEnabled = false;
final RxInt position = RxInt(0);
/// 响应数据
/// 带有Seconds的变量只在秒数更新时更新以避免频繁触发重绘
// 播放位置
Duration position = Duration.zero;
final RxInt positionSeconds = 0.obs;
int get positionInMilliseconds =>
videoPlayerController?.state.position.inMilliseconds ?? 0;
/// 进度条位置
Duration sliderPosition = Duration.zero;
final RxInt sliderPositionSeconds = 0.obs;
// 展示使用
final Rx<Duration> sliderTempPosition = Rx(Duration.zero);
final RxInt buffered = RxInt(0);
/// 视频时长
final Rx<Duration> duration = Rx(Duration.zero);
final RxInt duration = RxInt(0);
/// 视频缓冲
final Rx<Duration> buffered = Rx(Duration.zero);
final RxInt bufferedSeconds = 0.obs;
int durationInMilliseconds = 0;
void updateDuration(Duration value) {
duration.value = value.inSeconds;
durationInMilliseconds = value.inMilliseconds;
}
int _playerCount = 0;
@@ -111,44 +104,31 @@ class PlPlayerController with BlockConfigMixin {
final RxDouble _playbackSpeed = Pref.playSpeedDefault.obs;
late final RxDouble _longPressSpeed = Pref.longPressSpeedDefault.obs;
/// 音量控制条
final RxDouble volume = RxDouble(
PlatformUtils.isDesktop ? Pref.desktopVolume : 1.0,
);
final setSystemBrightness = Pref.setSystemBrightness;
/// 亮度控制条
final RxDouble brightness = (-1.0).obs;
/// 是否展示控制条
final RxBool showControls = false.obs;
/// 亮度控制条展示/隐藏
final RxBool showBrightnessStatus = false.obs;
/// 是否长按倍速
final RxBool longPressStatus = false.obs;
/// 屏幕锁 为true时关闭控制栏
final RxBool controlsLock = false.obs;
/// 全屏状态
final RxBool isFullScreen = false.obs;
// 默认投稿视频格式
bool isLive = false;
bool _isVertical = false;
/// 视频比例
final Rx<VideoFitType> videoFit = Rx(VideoFitType.contain);
final Rx<VideoFitType> videoFit = Rx(.contain);
/// 后台播放
late final RxBool continuePlayInBackground =
Pref.continuePlayInBackground.obs;
///
final RxBool isSliderMoving = false.obs;
bool _autoPlay = false;
// 记录历史记录
@@ -168,7 +148,7 @@ class PlPlayerController with BlockConfigMixin {
late DataSource dataSource;
Timer? _timer;
StreamSubscription<Duration>? _subForSeek;
StreamSubscription? _subForSeek;
Box setting = GStorage.setting;
@@ -387,8 +367,7 @@ class PlPlayerController with BlockConfigMixin {
? Pref.sliderDuration / 100
: Pref.sliderDuration * 1000;
num get sliderScale =>
isRelative ? duration.value.inMilliseconds * offset : offset;
num get sliderScale => isRelative ? durationInMilliseconds * offset : offset;
// 播放顺序相关
late PlayRepeat playRepeat = Pref.playRepeat;
@@ -441,27 +420,6 @@ class PlPlayerController with BlockConfigMixin {
putSubtitleSettings();
}
void updateSliderPositionSecond() {
int newSecond = sliderPosition.inSeconds;
if (sliderPositionSeconds.value != newSecond) {
sliderPositionSeconds.value = newSecond;
}
}
void updatePositionSecond() {
int newSecond = position.inSeconds;
if (positionSeconds.value != newSecond) {
positionSeconds.value = newSecond;
}
}
void updateBufferedSecond() {
int newSecond = buffered.value.inSeconds;
if (bufferedSeconds.value != newSecond) {
bufferedSeconds.value = newSecond;
}
}
static PlPlayerController? get instance => _instance;
static bool instanceExists() {
@@ -475,7 +433,6 @@ class PlPlayerController with BlockConfigMixin {
static PlayCallback? _playCallBack;
static Future<void>? playIfExists() {
// await _instance?.play(repeat: repeat, hideControls: hideControls);
return _playCallBack?.call();
}
@@ -688,14 +645,10 @@ class PlPlayerController with BlockConfigMixin {
return;
}
// 获取视频时长 00:00
this.duration.value = duration ?? _videoPlayerController!.state.duration;
position = buffered.value = sliderPosition = seekTo ?? Duration.zero;
updatePositionSecond();
updateSliderPositionSecond();
updateBufferedSecond();
// 数据加载完成
dataStatus.value = DataStatus.loaded;
updateDuration(duration ?? _videoPlayerController!.state.duration);
position.value = buffered.value = seekTo?.inSeconds ?? 0;
dataStatus.value = .loaded;
if (autoFullScreenFlag && autoEnterFullScreen) {
triggerFullScreen(status: true);
@@ -821,10 +774,7 @@ class PlPlayerController with BlockConfigMixin {
Volume? volume,
) async {
isBuffering.value = false;
buffered.value = Duration.zero;
_heartDuration = 0;
position = Duration.zero;
// 初始化时清空弹幕,防止上次重叠
danmakuController?.clear();
var player = _videoPlayerController;
@@ -906,7 +856,10 @@ class PlPlayerController with BlockConfigMixin {
return null;
}
if (_videoPlayerController case final ctr? when (ctr.current.isNotEmpty)) {
return ctr.open(ctr.current.last.copyWith(start: position), play: true);
return ctr.open(
ctr.current.last.copyWith(start: ctr.state.position),
play: true,
);
}
return null;
}
@@ -948,9 +901,10 @@ class PlPlayerController with BlockConfigMixin {
assert(_subscriptions == null);
final stream = player.stream;
_subscriptions = [
stream.playing.listen((event) {
WakelockPlus.toggle(enable: event);
if (event) {
/// playing
stream.playing.listen((bool playing) {
WakelockPlus.toggle(enable: playing);
if (playing) {
if (_isAutoEnterPip) {
if (_isCurrVideoPage) {
enterPip(autoEnter: true);
@@ -958,64 +912,68 @@ class PlPlayerController with BlockConfigMixin {
_disableAutoEnterPip();
}
}
playerStatus.value = PlayerStatus.playing;
playerStatus.value = .playing;
} else {
_disableAutoEnterPip();
playerStatus.value = PlayerStatus.paused;
playerStatus.value = .paused;
}
videoPlayerServiceHandler?.onStatusChange(
playerStatus.value,
isBuffering.value,
isLive,
);
/// 触发回调事件
for (final element in _statusListeners) {
element(event ? PlayerStatus.playing : PlayerStatus.paused);
element(playing ? .playing : .paused);
}
if (videoPlayerController!.state.position.inSeconds != 0) {
makeHeartBeat(positionSeconds.value, type: HeartBeatType.status);
final seconds = videoPlayerController!.state.position.inSeconds;
if (seconds != 0) {
makeHeartBeat(seconds, type: .status);
}
}),
stream.completed.listen((event) {
if (event) {
playerStatus.value = PlayerStatus.completed;
/// 触发回调事件
///completed
stream.completed.listen((bool completed) {
if (completed) {
playerStatus.value = .completed;
for (final element in _statusListeners) {
element(PlayerStatus.completed);
element(.completed);
}
} else {
// playerStatus.value = PlayerStatus.playing;
makeHeartBeat(-1, type: .completed);
}
makeHeartBeat(positionSeconds.value, type: HeartBeatType.completed);
}),
stream.position.listen((event) {
position = event;
updatePositionSecond();
if (!isSliderMoving.value) {
sliderPosition = event;
updateSliderPositionSecond();
/// position
stream.position.listen((Duration position) {
final posInSeconds = position.inSeconds;
if (posInSeconds != this.position.value) {
if (!isSeeking.value) {
this.position.value = posInSeconds;
}
videoPlayerServiceHandler?.onPositionChange(position);
}
/// 触发回调事件
for (final element in _positionListeners) {
element(event);
element(position);
}
makeHeartBeat(event.inSeconds);
makeHeartBeat(posInSeconds);
}),
stream.duration.listen((Duration event) {
duration.value = event;
stream.duration.listen(updateDuration),
stream.buffer.listen((Duration buffer) {
buffered.value = buffer.inSeconds;
}),
stream.buffer.listen((Duration event) {
buffered.value = event;
updateBufferedSecond();
}),
stream.buffering.listen((bool event) {
isBuffering.value = event;
stream.buffering.listen((bool buffering) {
isBuffering.value = buffering;
videoPlayerServiceHandler?.onStatusChange(
playerStatus.value,
event,
buffering,
isLive,
);
}),
@@ -1056,7 +1014,7 @@ class PlPlayerController with BlockConfigMixin {
// if (kDebugMode) {
// debugPrint("_buffered.value: ${_buffered.value}");
// }
if (isBuffering.value && buffered.value == Duration.zero) {
if (isBuffering.value && buffered.value == 0) {
SmartDialog.showToast(
'视频链接打开失败,重试中',
displayTime: const Duration(milliseconds: 500),
@@ -1079,16 +1037,6 @@ class PlPlayerController with BlockConfigMixin {
// SmartDialog.showToast('视频加载错误, $event');
}
}),
// controllerStream.volume.listen((event) {
// if (!mute.value && _volumeBeforeMute != event) {
// _volumeBeforeMute = event / 100;
// }
// }),
// 媒体通知监听
if (videoPlayerServiceHandler != null)
positionSeconds.listen((int event) {
videoPlayerServiceHandler!.onPositionChange(Duration(seconds: event));
}),
];
}
@@ -1108,17 +1056,12 @@ class PlPlayerController with BlockConfigMixin {
/// 跳转至指定位置
Future<void> seekTo(Duration position, {bool isSeek = true}) async {
// if (position >= duration.value) {
// position = duration.value - const Duration(milliseconds: 100);
// }
if (_playerCount == 0) {
return;
}
if (position < Duration.zero) {
position = Duration.zero;
}
this.position = position;
updatePositionSecond();
_heartDuration = position.inSeconds;
Future<void> seek() async {
@@ -1134,7 +1077,7 @@ class PlPlayerController with BlockConfigMixin {
}
}
if (duration.value != Duration.zero) {
if (duration.value != 0) {
seek();
} else {
// if (kDebugMode) debugPrint('seek duration else');
@@ -1214,42 +1157,22 @@ class PlPlayerController with BlockConfigMixin {
void hideTaskControls() {
_timer?.cancel();
_timer = Timer(showControlDuration, () {
if (!isSliderMoving.value && !tripling) {
if (!isSeeking.value && !tripling) {
controls = false;
}
_timer = null;
});
}
/// 调整播放时间
void onChangedSlider(int v) {
sliderPosition = Duration(seconds: v);
updateSliderPositionSecond();
}
void onChangedSliderStart([Duration? value]) {
if (value != null) {
sliderTempPosition.value = value;
}
isSliderMoving.value = true;
}
bool? cancelSeek;
bool? hasToast;
void onUpdatedSliderProgress(Duration value) {
sliderTempPosition.value = value;
sliderPosition = value;
updateSliderPositionSecond();
}
void onChangedSliderEnd() {
if (cancelSeek != true) {
void onSeekEnd() {
if (seekToPos != null) {
feedBack();
}
cancelSeek = null;
hasToast = null;
isSliderMoving.value = false;
if (showSeekPreview) {
showPreview.value = false;
}
hasToasted = false;
isSeeking.value = false;
hideTaskControls();
}
@@ -1350,13 +1273,9 @@ class PlPlayerController with BlockConfigMixin {
}
}
bool get _isCompleted =>
videoPlayerController!.state.completed ||
(duration.value - position).inMilliseconds <= 50;
// 双击播放、暂停
Future<void> onDoubleTapCenter() async {
if (!isLive && _isCompleted) {
if (!isLive && videoPlayerController!.state.completed) {
await videoPlayerController!.seek(Duration.zero);
videoPlayerController!.play();
} else {
@@ -1376,11 +1295,11 @@ class PlPlayerController with BlockConfigMixin {
}
void onForward(Duration duration) {
onForwardBackward(position + duration);
onForwardBackward(videoPlayerController!.state.position + duration);
}
void onBackward(Duration duration) {
onForwardBackward(position - duration);
onForwardBackward(videoPlayerController!.state.position - duration);
}
void onForwardBackward(Duration duration) {
@@ -1568,7 +1487,7 @@ class PlPlayerController with BlockConfigMixin {
}
case .completed:
if (playerStatus.isCompleted &&
(duration.value - position).inMilliseconds <= 1000) {
(durationInMilliseconds - positionInMilliseconds) <= 1000) {
progress = -1;
}
return send();
@@ -1734,7 +1653,7 @@ class PlPlayerController with BlockConfigMixin {
Future<void> takeScreenshot() async {
SmartDialog.showToast('截图中');
final time = DurationUtils.formatDuration(
position.inMilliseconds / 1000,
positionInMilliseconds / 1000,
).replaceAll(':', '-');
final image = await videoPlayerController?.screenshot();
if (image != null) {

View File

@@ -447,10 +447,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
BottomControlType.time => Obx(
() => _VideoTime(
position: DurationUtils.formatDuration(
plPlayerController.positionSeconds.value,
plPlayerController.position.value,
),
duration: DurationUtils.formatDuration(
plPlayerController.duration.value.inSeconds,
plPlayerController.duration.value,
),
),
),
@@ -961,6 +961,42 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
showRestoreScaleBtn.value = scale != 1.0;
}
void _onHorizontalDragStart() {
plPlayerController.isSeeking.value = true;
}
void _onHorizontalDragUpdate(double dx) {
final curPos =
plPlayerController.seekToPos?.inMilliseconds ??
plPlayerController.position.value * 1000;
final posDelta = (plPlayerController.sliderScale * dx / maxWidth).round();
final newPos = (curPos + posDelta).clamp(
0,
plPlayerController.durationInMilliseconds,
);
final seconds = newPos ~/ 1000;
plPlayerController
..seekToPos = Duration(milliseconds: newPos)
..position.value = seconds;
if (!plPlayerController.isFileSource &&
plPlayerController.showSeekPreview) {
plPlayerController.updatePreviewIndex(seconds);
}
}
void _onHorizontalDragEnd() {
plPlayerController.onSeekEnd();
if (plPlayerController.seekToPos case final seekToPos?) {
plPlayerController
..seekTo(seekToPos, isSeek: false)
..seekToPos = null;
} else {
plPlayerController.position.value =
plPlayerController.videoPlayerController?.state.position.inSeconds ??
0;
}
}
void _onPanUpdate(ScaleUpdateDetails details) {
if (_gestureType == null) {
final cumulativeDelta = details.localFocalPoint - _initialFocalPoint!;
@@ -968,6 +1004,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
final dx = cumulativeDelta.dx.abs();
final dy = cumulativeDelta.dy.abs();
if (dx > 3 * dy) {
_onHorizontalDragStart();
_gestureType = .horizontal;
} else if (dy > 3 * dx) {
if (!plPlayerController.enableSlideVolumeBrightness &&
@@ -1010,22 +1047,17 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// live模式下禁用
if (plPlayerController.isLive) return;
final int curSliderPosition =
plPlayerController.sliderPosition.inMilliseconds;
final int newPos =
(curSliderPosition +
(plPlayerController.sliderScale * delta.dx / maxWidth)
.round())
.clamp(0, plPlayerController.duration.value.inMilliseconds);
final Duration result = Duration(milliseconds: newPos);
final height = maxHeight * 0.125;
if (details.localFocalPoint.dy <= height &&
(details.localFocalPoint.dx >= maxWidth * 0.875 ||
details.localFocalPoint.dx <= maxWidth * 0.125)) {
plPlayerController.cancelSeek = true;
plPlayerController.showPreview.value = false;
if (plPlayerController.hasToast != true) {
plPlayerController.hasToast = true;
if (!plPlayerController.hasToasted) {
plPlayerController
..seekToPos = null
..hasToasted = true;
if (plPlayerController.showSeekPreview) {
plPlayerController.showPreview.value = false;
}
SmartDialog.showAttach(
targetContext: context,
alignment: Alignment.center,
@@ -1046,21 +1078,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
),
);
}
} else {
if (plPlayerController.cancelSeek == true) {
plPlayerController
..cancelSeek = null
..hasToast = null;
}
}
plPlayerController
..onUpdatedSliderProgress(result)
..onChangedSliderStart();
if (!plPlayerController.isFileSource &&
plPlayerController.showSeekPreview &&
plPlayerController.cancelSeek != true) {
plPlayerController.updatePreviewIndex(newPos ~/ 1000);
return;
} else if (plPlayerController.hasToasted) {
plPlayerController.hasToasted = false;
}
_onHorizontalDragUpdate(delta.dx);
} else if (_gestureType == .left) {
// 左边区域 👈
final double level = maxHeight * 3;
@@ -1110,21 +1133,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
}
void _onPanEnd(ScaleEndDetails details) {
if (plPlayerController.showSeekPreview) {
plPlayerController.showPreview.value = false;
}
if (plPlayerController.isSliderMoving.value) {
if (plPlayerController.cancelSeek == true) {
plPlayerController.onUpdatedSliderProgress(
plPlayerController.position,
);
} else {
plPlayerController.seekTo(
plPlayerController.sliderPosition,
isSeek: false,
);
}
plPlayerController.onChangedSliderEnd();
if (_gestureType == .horizontal) {
_onHorizontalDragEnd();
}
_initialFocalPoint = null;
_gestureType = null;
@@ -1274,6 +1284,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
final dx = pan.dx.abs();
final dy = pan.dy.abs();
if (dx > 3 * dy) {
_onHorizontalDragStart();
_gestureType = .horizontal;
} else if (dy > 3 * dx) {
_gestureType = .right;
@@ -1284,28 +1295,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
if (_gestureType == .horizontal) {
if (plPlayerController.isLive) return;
final delta = event.localPanDelta;
final int curSliderPosition =
plPlayerController.sliderPosition.inMilliseconds;
final int newPos =
(curSliderPosition +
(plPlayerController.sliderScale * delta.dx / maxWidth)
.round())
.clamp(0, plPlayerController.duration.value.inMilliseconds);
final Duration result = Duration(milliseconds: newPos);
if (plPlayerController.cancelSeek == true) {
plPlayerController
..cancelSeek = null
..hasToast = null;
}
plPlayerController
..onUpdatedSliderProgress(result)
..onChangedSliderStart();
if (!plPlayerController.isFileSource &&
plPlayerController.showSeekPreview &&
plPlayerController.cancelSeek != true) {
plPlayerController.updatePreviewIndex(newPos ~/ 1000);
}
_onHorizontalDragUpdate(event.localPanDelta.dx);
} else if (_gestureType == .right) {
if (!plPlayerController.enableSlideVolumeBrightness) {
return;
@@ -1328,11 +1318,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
}
void _onPointerPanZoomEnd(PointerPanZoomEndEvent event) {
plPlayerController.showPreview.value = false;
if (plPlayerController.isSliderMoving.value) {
plPlayerController
..seekTo(plPlayerController.sliderPosition, isSeek: false)
..onChangedSliderEnd();
if (_gestureType == .horizontal) {
_onHorizontalDragEnd();
}
_gestureType = null;
}
@@ -1455,9 +1442,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
child: Obx(
() => AnimatedOpacity(
curve: Curves.easeInOut,
opacity: plPlayerController.isSliderMoving.value
? 1.0
: 0.0,
opacity: plPlayerController.isSeeking.value ? 1.0 : 0.0,
duration: const Duration(milliseconds: 150),
child: Container(
decoration: const BoxDecoration(
@@ -1473,27 +1458,22 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() {
return Text(
Obx(
() => Text(
DurationUtils.formatDuration(
plPlayerController
.sliderTempPosition
.value
.inSeconds,
plPlayerController.position.value,
),
style: textStyle,
);
}),
),
),
const Text('/', style: textStyle),
Obx(
() {
return Text(
DurationUtils.formatDuration(
plPlayerController.duration.value.inSeconds,
),
style: textStyle,
);
},
() => Text(
DurationUtils.formatDuration(
plPlayerController.duration.value,
),
style: textStyle,
),
),
],
),
@@ -1727,20 +1707,18 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
case .alwaysShow:
offstage = showControls;
case .alwaysHide:
if (!plPlayerController.isSliderMoving.value) {
if (!plPlayerController.isSeeking.value) {
return const SizedBox.shrink();
}
offstage = showControls;
case .onlyShowFullScreen:
offstage =
showControls ||
(!isFullScreen &&
!plPlayerController.isSliderMoving.value);
(!isFullScreen && !plPlayerController.isSeeking.value);
case .onlyHideFullScreen:
offstage =
showControls ||
(isFullScreen &&
!plPlayerController.isSliderMoving.value);
(isFullScreen && !plPlayerController.isSeeking.value);
}
return Offstage(
offstage: offstage,
@@ -1748,17 +1726,11 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
clipBehavior: Clip.none,
alignment: Alignment.bottomCenter,
children: [
Obx(() {
final int value =
plPlayerController.sliderPositionSeconds.value;
final int max =
plPlayerController.duration.value.inSeconds;
final int buffer =
plPlayerController.bufferedSeconds.value;
return ProgressBar(
progress: Duration(seconds: value),
buffered: Duration(seconds: buffer),
total: Duration(seconds: max),
Obx(
() => ProgressBar(
progress: plPlayerController.position.value,
buffered: plPlayerController.buffered.value,
total: plPlayerController.duration.value,
progressBarColor: primary,
baseBarColor: const Color(0x33FFFFFF),
bufferedBarColor: bufferedBarColor,
@@ -1766,8 +1738,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
thumbGlowColor: thumbGlowColor,
barHeight: 3.5,
thumbRadius: 2.5,
);
}),
),
),
if (plPlayerController.enableBlock &&
videoDetailController.segmentProgressList.isNotEmpty)
Positioned(
@@ -1929,7 +1901,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
),
if (plPlayerController.isBuffering.value)
Obx(() {
if (plPlayerController.bufferedSeconds.value == 0) {
final buffered = plPlayerController.buffered.value;
if (buffered == 0) {
return const Text(
'加载中...',
style: TextStyle(
@@ -1938,10 +1911,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
),
);
}
String bufferStr = plPlayerController.buffered
.toString();
return Text(
bufferStr.substring(0, bufferStr.length - 3),
DurationUtils.formatDuration(buffered),
style: const TextStyle(
color: Colors.white,
fontSize: 12,
@@ -2087,11 +2058,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
);
}
late final segment = Pair(
first: plPlayerController.position.inMilliseconds / 1000.0,
second: plPlayerController.position.inMilliseconds / 1000.0,
);
Future<void> screenshotWebp() async {
final videoInfo = videoDetailController.data;
final ids = videoInfo.dash!.video!.map((i) => i.id!).toSet();
@@ -2103,8 +2069,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
final ctr = plPlayerController;
final theme = Theme.of(context);
final currentPos = ctr.position.inMilliseconds / 1000.0;
final duration = ctr.duration.value.inMilliseconds / 1000.0;
final currentPos = ctr.positionInMilliseconds / 1000.0;
final duration = ctr.durationInMilliseconds / 1000.0;
final segment = Pair(first: currentPos, second: currentPos);
final model = PostSegmentModel(
segment: segment,
category: SegmentType.sponsor,

View File

@@ -27,24 +27,22 @@ class BottomControl extends StatelessWidget {
void onDragStart(ThumbDragDetails duration) {
feedBack();
controller.onChangedSliderStart(duration.timeStamp);
controller
..position.value = duration.seconds
..isSeeking.value = true;
}
void onDragUpdate(ThumbDragDetails duration) {
if (!controller.isFileSource && controller.showSeekPreview) {
controller.updatePreviewIndex(duration.timeStamp.inSeconds);
controller.updatePreviewIndex(duration.seconds);
}
controller.onUpdatedSliderProgress(duration.timeStamp);
controller.position.value = duration.seconds;
}
void onSeek(Duration duration) {
if (controller.showSeekPreview) {
controller.showPreview.value = false;
}
void onSeek(int milliseconds) {
controller
..onChangedSliderEnd()
..onChangedSlider(duration.inSeconds)
..seekTo(Duration(seconds: duration.inSeconds), isSeek: false);
..onSeekEnd()
..seekTo(Duration(milliseconds: milliseconds), isSeek: false);
}
@override
@@ -70,15 +68,11 @@ class BottomControl extends StatelessWidget {
clipBehavior: Clip.none,
alignment: Alignment.bottomCenter,
children: [
Obx(() {
final int value = controller.sliderPositionSeconds.value;
final int max = controller.duration.value.inSeconds;
return ProgressBar(
progress: Duration(seconds: value),
buffered: Duration(
seconds: controller.bufferedSeconds.value,
),
total: Duration(seconds: max),
Obx(
() => ProgressBar(
progress: controller.position.value,
buffered: controller.buffered.value,
total: controller.duration.value,
progressBarColor: primary,
baseBarColor: const Color(0x33FFFFFF),
bufferedBarColor: bufferedBarColor,
@@ -90,8 +84,8 @@ class BottomControl extends StatelessWidget {
onDragStart: onDragStart,
onDragUpdate: onDragUpdate,
onSeek: onSeek,
);
}),
),
),
if (controller.enableBlock &&
videoDetailController.segmentProgressList.isNotEmpty)
Positioned(