opt video action

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-08-19 18:17:04 +08:00
parent 4f2bfb8126
commit 6c8baa5be5

View File

@@ -1010,6 +1010,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
color: Colors.white, color: Colors.white,
fontSize: 12, fontSize: 12,
); );
final isLive = plPlayerController.isLive;
return Stack( return Stack(
fit: StackFit.passthrough, fit: StackFit.passthrough,
@@ -1028,8 +1029,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
!plPlayerController.continuePlayInBackground.value, !plPlayerController.continuePlayInBackground.value,
resumeUponEnteringForegroundMode: true, resumeUponEnteringForegroundMode: true,
// 字幕尺寸调节 // 字幕尺寸调节
subtitleViewConfiguration: subtitleViewConfiguration: isLive
plPlayerController.subtitleConfig.value, ? const SubtitleViewConfiguration()
: plPlayerController.subtitleConfig.value,
fit: videoFit.boxFit, fit: videoFit.boxFit,
aspectRatio: videoFit.aspectRatio, aspectRatio: videoFit.aspectRatio,
dmWidget: widget.danmuWidget, dmWidget: widget.danmuWidget,
@@ -1047,10 +1049,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
onTap: () => plPlayerController.controls = onTap: () => plPlayerController.controls =
!plPlayerController.showControls.value, !plPlayerController.showControls.value,
onDoubleTapDown: onDoubleTapDown, onDoubleTapDown: onDoubleTapDown,
onLongPressStart: (_) => onLongPressStart: isLive
plPlayerController.setLongPressStatus(true), ? null
onLongPressEnd: (_) => : (_) => plPlayerController.setLongPressStatus(true),
plPlayerController.setLongPressStatus(false), onLongPressEnd: isLive
? null
: (_) => plPlayerController.setLongPressStatus(false),
enableDragSubtitle: plPlayerController.enableDragSubtitle, enableDragSubtitle: plPlayerController.enableDragSubtitle,
onUpdatePadding: plPlayerController.onUpdatePadding, onUpdatePadding: plPlayerController.onUpdatePadding,
); );
@@ -1062,31 +1066,35 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// Positioned.fill(top: 4, child: widget.danmuWidget!), // Positioned.fill(top: 4, child: widget.danmuWidget!),
/// 长按倍速 toast /// 长按倍速 toast
IgnorePointer( if (!isLive)
ignoring: true, IgnorePointer(
child: Align( ignoring: true,
alignment: Alignment.topCenter, child: Align(
child: FractionalTranslation( alignment: Alignment.topCenter,
translation: isFullScreen child: FractionalTranslation(
? const Offset(0.0, 1.2) translation: isFullScreen
: const Offset(0.0, 0.8), ? const Offset(0.0, 1.2)
child: Obx( : const Offset(0.0, 0.8),
() => AnimatedOpacity( child: Obx(
curve: Curves.easeInOut, () => AnimatedOpacity(
opacity: plPlayerController.longPressStatus.value ? 1.0 : 0.0, curve: Curves.easeInOut,
duration: const Duration(milliseconds: 150), opacity: plPlayerController.longPressStatus.value
child: Container( ? 1.0
padding: const EdgeInsets.all(6), : 0.0,
decoration: const BoxDecoration( duration: const Duration(milliseconds: 150),
color: Color(0x88000000), child: Container(
borderRadius: BorderRadius.all(Radius.circular(16)), padding: const EdgeInsets.all(6),
), decoration: const BoxDecoration(
child: Obx( color: Color(0x88000000),
() => Text( borderRadius: BorderRadius.all(Radius.circular(16)),
'${plPlayerController.enableAutoLongPressSpeed ? (plPlayerController.longPressStatus.value ? plPlayerController.lastPlaybackSpeed : plPlayerController.playbackSpeed) * 2 : plPlayerController.longPressSpeed}倍速中', ),
style: const TextStyle( child: Obx(
color: Colors.white, () => Text(
fontSize: 13, '${plPlayerController.enableAutoLongPressSpeed ? (plPlayerController.longPressStatus.value ? plPlayerController.lastPlaybackSpeed : plPlayerController.playbackSpeed) * 2 : plPlayerController.longPressSpeed}倍速中',
style: const TextStyle(
color: Colors.white,
fontSize: 13,
),
), ),
), ),
), ),
@@ -1095,69 +1103,71 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
), ),
), ),
), ),
),
/// 时间进度 toast /// 时间进度 toast
IgnorePointer( if (!isLive)
ignoring: true, IgnorePointer(
child: Align( ignoring: true,
alignment: Alignment.topCenter, child: Align(
child: FractionalTranslation( alignment: Alignment.topCenter,
translation: isFullScreen child: FractionalTranslation(
? const Offset(0.0, 1.2) translation: isFullScreen
: const Offset(0.0, 0.8), ? const Offset(0.0, 1.2)
child: Obx( : const Offset(0.0, 0.8),
() => AnimatedOpacity( child: Obx(
curve: Curves.easeInOut, () => AnimatedOpacity(
opacity: plPlayerController.isSliderMoving.value ? 1.0 : 0.0, curve: Curves.easeInOut,
duration: const Duration(milliseconds: 150), opacity: plPlayerController.isSliderMoving.value
child: Container( ? 1.0
decoration: const BoxDecoration( : 0.0,
color: Color(0x88000000), duration: const Duration(milliseconds: 150),
borderRadius: BorderRadius.all(Radius.circular(64)), child: Container(
), decoration: const BoxDecoration(
padding: const EdgeInsets.symmetric( color: Color(0x88000000),
horizontal: 10, borderRadius: BorderRadius.all(Radius.circular(64)),
vertical: 8, ),
), padding: const EdgeInsets.symmetric(
child: Row( horizontal: 10,
spacing: 2, vertical: 8,
mainAxisSize: MainAxisSize.min, ),
mainAxisAlignment: MainAxisAlignment.center, child: Row(
children: [ spacing: 2,
Obx(() { mainAxisSize: MainAxisSize.min,
return Text( mainAxisAlignment: MainAxisAlignment.center,
DurationUtil.formatDuration( children: [
plPlayerController Obx(() {
.sliderTempPosition
.value
.inSeconds,
),
style: textStyle,
);
}),
const Text('/', style: textStyle),
Obx(
() {
return Text( return Text(
DurationUtil.formatDuration( DurationUtil.formatDuration(
plPlayerController plPlayerController
.durationSeconds .sliderTempPosition
.value .value
.inSeconds, .inSeconds,
), ),
style: textStyle, style: textStyle,
); );
}, }),
), const Text('/', style: textStyle),
], Obx(
() {
return Text(
DurationUtil.formatDuration(
plPlayerController
.durationSeconds
.value
.inSeconds,
),
style: textStyle,
);
},
),
],
),
), ),
), ),
), ),
), ),
), ),
), ),
),
/// 音量🔊 控制条展示 /// 音量🔊 控制条展示
IgnorePointer( IgnorePointer(
@@ -1350,7 +1360,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
), ),
/// 进度条 live模式下禁用 /// 进度条 live模式下禁用
if (!plPlayerController.isLive && if (!isLive &&
plPlayerController.progressType != BtmProgressBehavior.alwaysHide) plPlayerController.progressType != BtmProgressBehavior.alwaysHide)
Positioned( Positioned(
bottom: -2.2, bottom: -2.2,
@@ -1453,7 +1463,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
), ),
), ),
if (!plPlayerController.isLive && plPlayerController.showSeekPreview) if (!isLive && plPlayerController.showSeekPreview)
buildSeekPreviewWidget( buildSeekPreviewWidget(
plPlayerController, plPlayerController,
maxWidth, maxWidth,
@@ -1461,36 +1471,39 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
), ),
// 锁 // 锁
SafeArea( if (!isLive)
child: Obx( SafeArea(
() => Visibility( child: Obx(
visible: !plPlayerController.isLive && isFullScreen, () => Visibility(
child: Align( visible: isFullScreen,
alignment: Alignment.centerLeft, child: Align(
child: FractionalTranslation( alignment: Alignment.centerLeft,
translation: const Offset(1, -0.4), child: FractionalTranslation(
child: Visibility( translation: const Offset(1, -0.4),
visible: child: Visibility(
plPlayerController.showControls.value && visible:
(isFullScreen || plPlayerController.controlsLock.value), plPlayerController.showControls.value &&
child: DecoratedBox( (isFullScreen ||
decoration: const BoxDecoration( plPlayerController.controlsLock.value),
color: Color(0x45000000), child: DecoratedBox(
borderRadius: BorderRadius.all(Radius.circular(8)), decoration: const BoxDecoration(
), color: Color(0x45000000),
child: ComBtn( borderRadius: BorderRadius.all(Radius.circular(8)),
icon: Icon(
plPlayerController.controlsLock.value
? FontAwesomeIcons.lock
: FontAwesomeIcons.lockOpen,
semanticLabel: plPlayerController.controlsLock.value
? '解锁'
: '锁定',
size: 15,
color: Colors.white,
), ),
onTap: () => plPlayerController.onLockControl( child: ComBtn(
!plPlayerController.controlsLock.value, icon: Icon(
plPlayerController.controlsLock.value
? FontAwesomeIcons.lock
: FontAwesomeIcons.lockOpen,
semanticLabel: plPlayerController.controlsLock.value
? '解锁'
: '锁定',
size: 15,
color: Colors.white,
),
onTap: () => plPlayerController.onLockControl(
!plPlayerController.controlsLock.value,
),
), ),
), ),
), ),
@@ -1499,7 +1512,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
), ),
), ),
), ),
),
// 截图 // 截图
SafeArea( SafeArea(
@@ -1647,75 +1659,79 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
}), }),
/// 点击 快进/快退 /// 点击 快进/快退
Obx( if (!isLive)
() => _mountSeekBackwardButton.value || _mountSeekForwardButton.value Obx(
? Positioned.fill( () =>
child: Row( _mountSeekBackwardButton.value || _mountSeekForwardButton.value
children: [ ? Positioned.fill(
if (_mountSeekBackwardButton.value) child: Row(
Expanded( children: [
child: TweenAnimationBuilder<double>( if (_mountSeekBackwardButton.value)
tween: Tween<double>(begin: 0.0, end: 1.0), Expanded(
duration: const Duration(milliseconds: 500), child: TweenAnimationBuilder<double>(
builder: (context, value, child) => Opacity( tween: Tween<double>(begin: 0.0, end: 1.0),
opacity: value, duration: const Duration(milliseconds: 500),
child: child, builder: (context, value, child) => Opacity(
), opacity: value,
child: BackwardSeekIndicator( child: child,
duration: ),
plPlayerController.fastForBackwardDuration, child: BackwardSeekIndicator(
onSubmitted: (Duration value) { duration:
_mountSeekBackwardButton.value = false; plPlayerController.fastForBackwardDuration,
final Player player = widget onSubmitted: (Duration value) {
.plPlayerController _mountSeekBackwardButton.value = false;
.videoPlayerController!; final Player player = widget
Duration result = player.state.position - value; .plPlayerController
result = result.clamp( .videoPlayerController!;
Duration.zero, Duration result =
player.state.duration, player.state.position - value;
); result = result.clamp(
plPlayerController Duration.zero,
..seekTo(result, isSeek: false) player.state.duration,
..play(); );
}, plPlayerController
..seekTo(result, isSeek: false)
..play();
},
),
), ),
), ),
), const Spacer(flex: 2),
const Spacer(flex: 2), if (_mountSeekForwardButton.value)
if (_mountSeekForwardButton.value) Expanded(
Expanded( child: TweenAnimationBuilder<double>(
child: TweenAnimationBuilder<double>( tween: Tween<double>(begin: 0.0, end: 1.0),
tween: Tween<double>(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 500),
duration: const Duration(milliseconds: 500), builder: (context, value, child) => Opacity(
builder: (context, value, child) => Opacity( opacity: value,
opacity: value, child: child,
child: child, ),
), child: ForwardSeekIndicator(
child: ForwardSeekIndicator( duration:
duration: plPlayerController.fastForBackwardDuration,
plPlayerController.fastForBackwardDuration, onSubmitted: (Duration value) {
onSubmitted: (Duration value) { _mountSeekForwardButton.value = false;
_mountSeekForwardButton.value = false; final Player player = widget
final Player player = widget .plPlayerController
.plPlayerController .videoPlayerController!;
.videoPlayerController!; Duration result =
Duration result = player.state.position + value; player.state.position + value;
result = result.clamp( result = result.clamp(
Duration.zero, Duration.zero,
player.state.duration, player.state.duration,
); );
plPlayerController plPlayerController
..seekTo(result, isSeek: false) ..seekTo(result, isSeek: false)
..play(); ..play();
}, },
),
), ),
), ),
), ],
], ),
), )
) : const SizedBox.shrink(),
: const SizedBox.shrink(), ),
),
], ],
); );
} }