mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-01 00:28:18 +08:00
custom video aspectRatio
Closes #1040 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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];
|
|
||||||
}
|
|
||||||
|
|||||||
22
lib/plugin/pl_player/models/video_fit_type.dart
Normal file
22
lib/plugin/pl_player/models/video_fit_type.dart
Normal 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,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
),
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
// /// 弹幕面板
|
// /// 弹幕面板
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user