custom video aspectRatio

Closes #1040

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-08-17 21:50:21 +08:00
parent 470545337d
commit dc6b76812c
5 changed files with 426 additions and 421 deletions

View File

@@ -1,5 +1,6 @@
import 'package:PiliPlus/pages/live_room/controller.dart'; import 'package:PiliPlus/pages/live_room/controller.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart';
import 'package:PiliPlus/plugin/pl_player/models/video_fit_type.dart';
import 'package:PiliPlus/plugin/pl_player/widgets/common_btn.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/common_btn.dart';
import 'package:PiliPlus/plugin/pl_player/widgets/play_pause_btn.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/play_pause_btn.dart';
import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage.dart';
@@ -97,13 +98,13 @@ class BottomControl extends StatelessWidget {
}, },
), ),
Obx( Obx(
() => PopupMenuButton<BoxFit>( () => PopupMenuButton<VideoFitType>(
initialValue: plPlayerController.videoFit.value, initialValue: plPlayerController.videoFit.value,
color: Colors.black.withValues(alpha: 0.8), color: Colors.black.withValues(alpha: 0.8),
itemBuilder: (context) { itemBuilder: (context) {
return BoxFit.values return VideoFitType.values
.map( .map(
(BoxFit boxFit) => PopupMenuItem<BoxFit>( (boxFit) => PopupMenuItem<VideoFitType>(
height: 35, height: 35,
padding: const EdgeInsets.only(left: 30), padding: const EdgeInsets.only(left: 30),
value: boxFit, value: boxFit,

View File

@@ -25,6 +25,7 @@ import 'package:PiliPlus/plugin/pl_player/models/fullscreen_mode.dart';
import 'package:PiliPlus/plugin/pl_player/models/heart_beat_type.dart'; import 'package:PiliPlus/plugin/pl_player/models/heart_beat_type.dart';
import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart'; import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart';
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart'; import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
import 'package:PiliPlus/plugin/pl_player/models/video_fit_type.dart';
import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart'; import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart';
import 'package:PiliPlus/services/service_locator.dart'; import 'package:PiliPlus/services/service_locator.dart';
import 'package:PiliPlus/utils/accounts.dart'; import 'package:PiliPlus/utils/accounts.dart';
@@ -104,7 +105,7 @@ class PlPlayerController {
bool _isVertical = false; bool _isVertical = false;
final Rx<BoxFit> _videoFit = Rx(BoxFit.contain); final Rx<VideoFitType> _videoFit = Rx(VideoFitType.contain);
late StreamSubscription<DataStatus> _dataListenerForVideoFit; late StreamSubscription<DataStatus> _dataListenerForVideoFit;
late StreamSubscription<DataStatus> _dataListenerForEnterFullscreen; late StreamSubscription<DataStatus> _dataListenerForEnterFullscreen;
@@ -220,7 +221,7 @@ class PlPlayerController {
bool get autoplay => _autoPlay; bool get autoplay => _autoPlay;
/// 视频比例 /// 视频比例
Rx<BoxFit> get videoFit => _videoFit; Rx<VideoFitType> get videoFit => _videoFit;
/// 后台播放 /// 后台播放
RxBool get continuePlayInBackground => _continuePlayInBackground; RxBool get continuePlayInBackground => _continuePlayInBackground;
@@ -370,8 +371,9 @@ class PlPlayerController {
: Colors.black.withValues(alpha: subtitleBgOpaticy), : Colors.black.withValues(alpha: subtitleBgOpaticy),
); );
SubtitleViewConfiguration get subtitleViewConfiguration => late final Rx<SubtitleViewConfiguration> subtitleConfig = _getSubConfig.obs;
SubtitleViewConfiguration(
SubtitleViewConfiguration get _getSubConfig => SubtitleViewConfiguration(
style: subTitleStyle, style: subTitleStyle,
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: subtitlePaddingH.toDouble(), left: subtitlePaddingH.toDouble(),
@@ -382,12 +384,8 @@ class PlPlayerController {
strokeWidth: subtitleBgOpaticy == 0 ? subtitleStrokeWidth : null, strokeWidth: subtitleBgOpaticy == 0 ? subtitleStrokeWidth : null,
); );
GlobalKey<VideoState> Function()? getPlayerKey;
void updateSubtitleStyle() { void updateSubtitleStyle() {
getPlayerKey?.call().currentState?.update( subtitleConfig.value = _getSubConfig;
subtitleViewConfiguration: subtitleViewConfiguration,
);
} }
void onUpdatePadding(EdgeInsets padding) { void onUpdatePadding(EdgeInsets padding) {
@@ -1271,42 +1269,32 @@ class PlPlayerController {
} }
/// Toggle Change the videofit accordingly /// Toggle Change the videofit accordingly
void toggleVideoFit(BoxFit value) { void toggleVideoFit(VideoFitType value) {
_videoFit.value = value; _videoFit.value = value;
setVideoFit();
getPlayerKey?.call().currentState?.update(fit: value);
}
/// 缓存fit
Future<void> setVideoFit() async {
SmartDialog.showToast(
_videoFit.value.toast,
displayTime: const Duration(seconds: 1),
);
video.put(VideoBoxKey.cacheVideoFit, _videoFit.value.index); video.put(VideoBoxKey.cacheVideoFit, _videoFit.value.index);
} }
/// 读取fit /// 读取fit
int fitValue = Pref.cacheVideoFit; int fitValue = Pref.cacheVideoFit;
Future<void> getVideoFit() async { Future<void> getVideoFit() async {
var attr = BoxFit.values[fitValue]; var attr = VideoFitType.values[fitValue];
// 由于none与scaleDown涉及视频原始尺寸需要等待视频加载后再设置否则尺寸会变为0出现错误; // 由于none与scaleDown涉及视频原始尺寸需要等待视频加载后再设置否则尺寸会变为0出现错误;
if (attr == BoxFit.none || attr == BoxFit.scaleDown) { if (attr == VideoFitType.none || attr == VideoFitType.scaleDown) {
if (buffered.value == Duration.zero) { if (buffered.value == Duration.zero) {
attr = BoxFit.contain; attr = VideoFitType.contain;
_dataListenerForVideoFit = dataStatus.status.listen((status) { _dataListenerForVideoFit = dataStatus.status.listen((status) {
if (status == DataStatus.loaded) { if (status == DataStatus.loaded) {
_dataListenerForVideoFit.cancel(); _dataListenerForVideoFit.cancel();
var attr = BoxFit.values[fitValue]; var attr = VideoFitType.values[fitValue];
if (attr == BoxFit.none || attr == BoxFit.scaleDown) { if (attr == VideoFitType.none || attr == VideoFitType.scaleDown) {
_videoFit.value = attr; _videoFit.value = attr;
} }
} }
}); });
} }
// fill不应该在竖屏视频生效 // fill不应该在竖屏视频生效
} else if (attr == BoxFit.fill && isVertical) { } else if (attr == VideoFitType.fill && isVertical) {
attr = BoxFit.contain; attr = VideoFitType.contain;
} }
_videoFit.value = attr; _videoFit.value = attr;
} }
@@ -1676,17 +1664,3 @@ class PlPlayerController {
late final RxList<double> dmTrend = <double>[].obs; late final RxList<double> dmTrend = <double>[].obs;
late final RxBool showDmTreandChart = true.obs; late final RxBool showDmTreandChart = true.obs;
} }
extension BoxFitExt on BoxFit {
String get desc => const ['拉伸', '自动', '裁剪', '等宽', '等高', '原始', '限制'][index];
String get toast => const [
'拉伸至播放器尺寸,将产生变形(竖屏改为自动)',
'缩放至播放器尺寸,保留黑边',
'缩放至填满播放器,裁剪超出部分',
'缩放至撑满播放器宽度',
'缩放至撑满播放器高度',
'不缩放,以视频原始尺寸显示',
'仅超出时缩小至播放器尺寸',
][index];
}

View File

@@ -0,0 +1,22 @@
import 'package:flutter/material.dart' show BoxFit;
enum VideoFitType {
fill('拉伸', boxFit: BoxFit.fill),
contain('自动', boxFit: BoxFit.contain),
cover('裁剪', boxFit: BoxFit.cover),
fitWidth('等宽', boxFit: BoxFit.fitWidth),
fitHeight('等高', boxFit: BoxFit.fitHeight),
none('原始', boxFit: BoxFit.none),
scaleDown('限制', boxFit: BoxFit.scaleDown),
ratio_4x3('4:3', aspectRatio: 4 / 3),
ratio_16x9('16:9', aspectRatio: 16 / 9);
final String desc;
final BoxFit boxFit;
final double? aspectRatio;
const VideoFitType(
this.desc, {
this.boxFit = BoxFit.contain,
this.aspectRatio,
});
}

View File

@@ -21,6 +21,7 @@ import 'package:PiliPlus/plugin/pl_player/models/double_tap_type.dart';
import 'package:PiliPlus/plugin/pl_player/models/duration.dart'; import 'package:PiliPlus/plugin/pl_player/models/duration.dart';
import 'package:PiliPlus/plugin/pl_player/models/fullscreen_mode.dart'; import 'package:PiliPlus/plugin/pl_player/models/fullscreen_mode.dart';
import 'package:PiliPlus/plugin/pl_player/models/gesture_type.dart'; import 'package:PiliPlus/plugin/pl_player/models/gesture_type.dart';
import 'package:PiliPlus/plugin/pl_player/models/video_fit_type.dart';
import 'package:PiliPlus/plugin/pl_player/widgets/app_bar_ani.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/app_bar_ani.dart';
import 'package:PiliPlus/plugin/pl_player/widgets/backward_seek.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/backward_seek.dart';
import 'package:PiliPlus/plugin/pl_player/widgets/bottom_control.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/bottom_control.dart';
@@ -167,7 +168,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
plPlayerController.getPlayerKey = () => key;
_controlsListener = plPlayerController.showControls.listen((bool val) { _controlsListener = plPlayerController.showControls.listen((bool val) {
final visible = val && !plPlayerController.controlsLock.value; final visible = val && !plPlayerController.controlsLock.value;
visible ? animationController.forward() : animationController.reverse(); visible ? animationController.forward() : animationController.reverse();
@@ -379,6 +379,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 超分辨率 /// 超分辨率
BottomControlType.superResolution => Obx( BottomControlType.superResolution => Obx(
() => PopupMenuButton<SuperResolutionType>( () => PopupMenuButton<SuperResolutionType>(
requestFocus: false,
initialValue: plPlayerController.superResolutionType.value, initialValue: plPlayerController.superResolutionType.value,
color: Colors.black.withValues(alpha: 0.8), color: Colors.black.withValues(alpha: 0.8),
itemBuilder: (context) { itemBuilder: (context) {
@@ -485,13 +486,14 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 画面比例 /// 画面比例
BottomControlType.fit => Obx( BottomControlType.fit => Obx(
() => PopupMenuButton<BoxFit>( () => PopupMenuButton<VideoFitType>(
requestFocus: false,
initialValue: plPlayerController.videoFit.value, initialValue: plPlayerController.videoFit.value,
color: Colors.black.withValues(alpha: 0.8), color: Colors.black.withValues(alpha: 0.8),
itemBuilder: (context) { itemBuilder: (context) {
return BoxFit.values return VideoFitType.values
.map( .map(
(BoxFit boxFit) => PopupMenuItem<BoxFit>( (boxFit) => PopupMenuItem<VideoFitType>(
height: 35, height: 35,
padding: const EdgeInsets.only(left: 30), padding: const EdgeInsets.only(left: 30),
value: boxFit, value: boxFit,
@@ -519,6 +521,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
() => widget.videoDetailController?.subtitles.isEmpty == true () => widget.videoDetailController?.subtitles.isEmpty == true
? const SizedBox.shrink() ? const SizedBox.shrink()
: PopupMenuButton<int>( : PopupMenuButton<int>(
requestFocus: false,
initialValue: widget initialValue: widget
.videoDetailController! .videoDetailController!
.vttSubtitlesIndex .vttSubtitlesIndex
@@ -570,6 +573,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 播放速度 /// 播放速度
BottomControlType.speed => Obx( BottomControlType.speed => Obx(
() => PopupMenuButton<double>( () => PopupMenuButton<double>(
requestFocus: false,
initialValue: plPlayerController.playbackSpeed, initialValue: plPlayerController.playbackSpeed,
color: Colors.black.withValues(alpha: 0.8), color: Colors.black.withValues(alpha: 0.8),
itemBuilder: (context) { itemBuilder: (context) {
@@ -670,41 +674,11 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
late final transformationController = TransformationController(); late final transformationController = TransformationController();
@override late ThemeData theme;
Widget build(BuildContext context) { late double maxWidth;
final ThemeData theme = Theme.of(context); late double maxHeight;
final Color primary = theme.colorScheme.primary;
const TextStyle textStyle = TextStyle(
color: Colors.white,
fontSize: 12,
);
final maxWidth = widget.maxWidth; void _onInteractionStart(ScaleStartDetails details) {
final maxHeight = widget.maxHeight;
return Stack(
fit: StackFit.passthrough,
key: _playerKey,
children: <Widget>[
Obx(
() => Video(
fill: widget.fill ?? Colors.black,
key: key,
alignment: widget.alignment ?? Alignment.center,
controller: videoController,
controls: NoVideoControls,
pauseUponEnteringBackgroundMode:
!plPlayerController.continuePlayInBackground.value,
resumeUponEnteringForegroundMode: true,
// 字幕尺寸调节
subtitleViewConfiguration:
plPlayerController.subtitleViewConfiguration,
fit: plPlayerController.videoFit.value,
dmWidget: widget.danmuWidget,
transformationController: transformationController,
scaleEnabled: !plPlayerController.controlsLock.value,
enableShrinkVideoSize: plPlayerController.enableShrinkVideoSize,
onInteractionStart: (ScaleStartDetails details) {
if (plPlayerController.controlsLock.value) return; if (plPlayerController.controlsLock.value) return;
// 如果起点太靠上则屏蔽 // 如果起点太靠上则屏蔽
if (details.localFocalPoint.dy < 40) return; if (details.localFocalPoint.dy < 40) return;
@@ -719,13 +693,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// debugPrint("_initialFocalPoint$_initialFocalPoint"); // debugPrint("_initialFocalPoint$_initialFocalPoint");
// } // }
_gestureType = null; _gestureType = null;
}, }
onInteractionUpdate: (ScaleUpdateDetails details) {
showRestoreScaleBtn.value = void _onInteractionUpdate(ScaleUpdateDetails details) {
transformationController.value.row0.x != 1.0; showRestoreScaleBtn.value = transformationController.value.row0.x != 1.0;
if (interacting || _initialFocalPoint == Offset.zero) return; if (interacting || _initialFocalPoint == Offset.zero) return;
Offset cumulativeDelta = Offset cumulativeDelta = details.localFocalPoint - _initialFocalPoint;
details.localFocalPoint - _initialFocalPoint;
if (details.pointerCount == 2 && cumulativeDelta.distance < 1.5) { if (details.pointerCount == 2 && cumulativeDelta.distance < 1.5) {
interacting = true; interacting = true;
_gestureType = null; _gestureType = null;
@@ -739,8 +712,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
if (cumulativeDelta.distance < 1) return; if (cumulativeDelta.distance < 1) return;
if (cumulativeDelta.dx.abs() > 3 * cumulativeDelta.dy.abs()) { if (cumulativeDelta.dx.abs() > 3 * cumulativeDelta.dy.abs()) {
_gestureType = GestureType.horizontal; _gestureType = GestureType.horizontal;
} else if (cumulativeDelta.dy.abs() > } else if (cumulativeDelta.dy.abs() > 3 * cumulativeDelta.dx.abs()) {
3 * cumulativeDelta.dx.abs()) {
if (!plPlayerController.enableSlideVolumeBrightness && if (!plPlayerController.enableSlideVolumeBrightness &&
!plPlayerController.enableSlideFS) { !plPlayerController.enableSlideFS) {
return; return;
@@ -784,9 +756,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
plPlayerController.sliderPosition.value.inMilliseconds; plPlayerController.sliderPosition.value.inMilliseconds;
final int newPos = final int newPos =
(curSliderPosition + (curSliderPosition +
(plPlayerController.sliderScale * (plPlayerController.sliderScale * delta.dx / maxWidth)
delta.dx /
maxWidth)
.round()) .round())
.clamp( .clamp(
0, 0,
@@ -845,15 +815,13 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
} else if (_gestureType == GestureType.left) { } else if (_gestureType == GestureType.left) {
// 左边区域 👈 // 左边区域 👈
final double level = maxHeight * 3; final double level = maxHeight * 3;
final double brightness = final double brightness = _brightnessValue.value - delta.dy / level;
_brightnessValue.value - delta.dy / level;
final double result = brightness.clamp(0.0, 1.0); final double result = brightness.clamp(0.0, 1.0);
setBrightness(result); setBrightness(result);
} else if (_gestureType == GestureType.center) { } else if (_gestureType == GestureType.center) {
// 全屏 // 全屏
const double threshold = 2.5; // 滑动阈值 const double threshold = 2.5; // 滑动阈值
double cumulativeDy = double cumulativeDy = details.localFocalPoint.dy - _initialFocalPoint.dy;
details.localFocalPoint.dy - _initialFocalPoint.dy;
void fullScreenTrigger(bool status) { void fullScreenTrigger(bool status) {
plPlayerController.triggerFullScreen(status: status); plPlayerController.triggerFullScreen(status: status);
@@ -861,8 +829,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
if (cumulativeDy > threshold) { if (cumulativeDy > threshold) {
_gestureType = GestureType.center_down; _gestureType = GestureType.center_down;
if (isFullScreen ^ if (isFullScreen ^ plPlayerController.fullScreenGestureReverse) {
plPlayerController.fullScreenGestureReverse) {
fullScreenTrigger( fullScreenTrigger(
plPlayerController.fullScreenGestureReverse, plPlayerController.fullScreenGestureReverse,
); );
@@ -870,8 +837,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// if (kDebugMode) debugPrint('center_down:$cumulativeDy'); // if (kDebugMode) debugPrint('center_down:$cumulativeDy');
} else if (cumulativeDy < -threshold) { } else if (cumulativeDy < -threshold) {
_gestureType = GestureType.center_up; _gestureType = GestureType.center_up;
if (!isFullScreen ^ if (!isFullScreen ^ plPlayerController.fullScreenGestureReverse) {
plPlayerController.fullScreenGestureReverse) {
fullScreenTrigger( fullScreenTrigger(
!plPlayerController.fullScreenGestureReverse, !plPlayerController.fullScreenGestureReverse,
); );
@@ -891,8 +857,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
}, },
); );
} }
}, }
onInteractionEnd: (ScaleEndDetails details) {
void _onInteractionEnd(ScaleEndDetails details) {
if (plPlayerController.showSeekPreview) { if (plPlayerController.showSeekPreview) {
plPlayerController.showPreview.value = false; plPlayerController.showPreview.value = false;
} }
@@ -912,10 +879,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
interacting = false; interacting = false;
_initialFocalPoint = Offset.zero; _initialFocalPoint = Offset.zero;
_gestureType = null; _gestureType = null;
}, }
flipX: plPlayerController.flipX.value,
flipY: plPlayerController.flipY.value, void onVerticalDragStart(DragStartDetails details) {
onVerticalDragStart: (details) {
if (plPlayerController.controlsLock.value) return; if (plPlayerController.controlsLock.value) return;
if (details.localPosition.dy < 40) return; if (details.localPosition.dy < 40) return;
if (details.localPosition.dx < 40) return; if (details.localPosition.dx < 40) return;
@@ -923,8 +889,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
if (details.localPosition.dy > maxHeight - 40) return; if (details.localPosition.dy > maxHeight - 40) return;
_initialFocalPoint = details.localPosition; _initialFocalPoint = details.localPosition;
_gestureType = null; _gestureType = null;
}, }
onVerticalDragUpdate: (details) {
void onVerticalDragUpdate(DragUpdateDetails details) {
if (plPlayerController.controlsLock.value) return; if (plPlayerController.controlsLock.value) return;
if (!plPlayerController.enableSlideVolumeBrightness && if (!plPlayerController.enableSlideVolumeBrightness &&
!plPlayerController.enableSlideFS) { !plPlayerController.enableSlideFS) {
@@ -968,8 +935,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
} else if (_gestureType == GestureType.center) { } else if (_gestureType == GestureType.center) {
// 全屏 // 全屏
const double threshold = 2.5; // 滑动阈值 const double threshold = 2.5; // 滑动阈值
double cumulativeDy = double cumulativeDy = details.localPosition.dy - _initialFocalPoint.dy;
details.localPosition.dy - _initialFocalPoint.dy;
void fullScreenTrigger(bool status) { void fullScreenTrigger(bool status) {
plPlayerController.triggerFullScreen(status: status); plPlayerController.triggerFullScreen(status: status);
@@ -977,8 +943,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
if (cumulativeDy > threshold) { if (cumulativeDy > threshold) {
_gestureType = GestureType.center_down; _gestureType = GestureType.center_down;
if (isFullScreen ^ if (isFullScreen ^ plPlayerController.fullScreenGestureReverse) {
plPlayerController.fullScreenGestureReverse) {
fullScreenTrigger( fullScreenTrigger(
plPlayerController.fullScreenGestureReverse, plPlayerController.fullScreenGestureReverse,
); );
@@ -986,8 +951,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// if (kDebugMode) debugPrint('center_down:$cumulativeDy'); // if (kDebugMode) debugPrint('center_down:$cumulativeDy');
} else if (cumulativeDy < -threshold) { } else if (cumulativeDy < -threshold) {
_gestureType = GestureType.center_up; _gestureType = GestureType.center_up;
if (!isFullScreen ^ if (!isFullScreen ^ plPlayerController.fullScreenGestureReverse) {
plPlayerController.fullScreenGestureReverse) {
fullScreenTrigger( fullScreenTrigger(
!plPlayerController.fullScreenGestureReverse, !plPlayerController.fullScreenGestureReverse,
); );
@@ -1001,24 +965,21 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
'setVolume', 'setVolume',
const Duration(milliseconds: 20), const Duration(milliseconds: 20),
() { () {
final double volume = final double volume = _volumeValue.value - details.delta.dy / level;
_volumeValue.value - details.delta.dy / level;
final double result = volume.clamp(0.0, 1.0); final double result = volume.clamp(0.0, 1.0);
setVolume(result); setVolume(result);
}, },
); );
} }
}, }
onVerticalDragEnd: (details) {
void onVerticalDragEnd(DragEndDetails details) {
interacting = false; interacting = false;
_initialFocalPoint = Offset.zero; _initialFocalPoint = Offset.zero;
_gestureType = null; _gestureType = null;
}, }
onTap: () {
plPlayerController.controls = void onDoubleTapDown(TapDownDetails details) {
!plPlayerController.showControls.value;
},
onDoubleTapDown: (TapDownDetails details) {
if (plPlayerController.controlsLock.value) { if (plPlayerController.controlsLock.value) {
return; return;
} }
@@ -1037,16 +998,63 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
type = DoubleTapType.right; type = DoubleTapType.right;
} }
doubleTapFuc(type); doubleTapFuc(type);
}, }
onLongPressStart: (LongPressStartDetails detail) {
plPlayerController.setLongPressStatus(true); @override
}, Widget build(BuildContext context) {
onLongPressEnd: (LongPressEndDetails details) { theme = Theme.of(context);
plPlayerController.setLongPressStatus(false); maxWidth = widget.maxWidth;
}, maxHeight = widget.maxHeight;
final Color primary = theme.colorScheme.primary;
const TextStyle textStyle = TextStyle(
color: Colors.white,
fontSize: 12,
);
return Stack(
fit: StackFit.passthrough,
key: _playerKey,
children: <Widget>[
Obx(
() {
final videoFit = plPlayerController.videoFit.value;
return Video(
fill: widget.fill ?? Colors.black,
key: key,
alignment: widget.alignment ?? Alignment.center,
controller: videoController,
controls: NoVideoControls,
pauseUponEnteringBackgroundMode:
!plPlayerController.continuePlayInBackground.value,
resumeUponEnteringForegroundMode: true,
// 字幕尺寸调节
subtitleViewConfiguration:
plPlayerController.subtitleConfig.value,
fit: videoFit.boxFit,
aspectRatio: videoFit.aspectRatio,
dmWidget: widget.danmuWidget,
transformationController: transformationController,
scaleEnabled: !plPlayerController.controlsLock.value,
enableShrinkVideoSize: plPlayerController.enableShrinkVideoSize,
onInteractionStart: _onInteractionStart,
onInteractionUpdate: _onInteractionUpdate,
onInteractionEnd: _onInteractionEnd,
flipX: plPlayerController.flipX.value,
flipY: plPlayerController.flipY.value,
onVerticalDragStart: onVerticalDragStart,
onVerticalDragUpdate: onVerticalDragUpdate,
onVerticalDragEnd: onVerticalDragEnd,
onTap: () => plPlayerController.controls =
!plPlayerController.showControls.value,
onDoubleTapDown: onDoubleTapDown,
onLongPressStart: (_) =>
plPlayerController.setLongPressStatus(true),
onLongPressEnd: (_) =>
plPlayerController.setLongPressStatus(false),
enableDragSubtitle: plPlayerController.enableDragSubtitle, enableDragSubtitle: plPlayerController.enableDragSubtitle,
onUpdatePadding: plPlayerController.onUpdatePadding, onUpdatePadding: plPlayerController.onUpdatePadding,
), );
},
), ),
// /// 弹幕面板 // /// 弹幕面板

View File

@@ -1225,7 +1225,7 @@ packages:
description: description:
path: media_kit_video path: media_kit_video
ref: "version_1.2.5" ref: "version_1.2.5"
resolved-ref: a74d1af2bcc6b5c88b2216c594e7e3eba0c7cee5 resolved-ref: "69fbf92def88d4304fc177fa4dd14664c0c2d8d5"
url: "https://github.com/bggRGjQaUbCoE/media-kit.git" url: "https://github.com/bggRGjQaUbCoE/media-kit.git"
source: git source: git
version: "1.2.5" version: "1.2.5"