mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-11 04:27:47 +08:00
improve player gesture
Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
@@ -129,7 +129,7 @@ class PLVideoPlayer extends StatefulWidget {
|
||||
|
||||
class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
with WidgetsBindingObserver, TickerProviderStateMixin {
|
||||
late AnimationController animationController;
|
||||
late AnimationController _animationController;
|
||||
late VideoController videoController;
|
||||
late final CommonIntroController introController = widget.introController!;
|
||||
late final VideoDetailController videoDetailController =
|
||||
@@ -147,15 +147,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
late final RxBool showRestoreScaleBtn = false.obs;
|
||||
|
||||
GestureType? _gestureType;
|
||||
|
||||
Offset initialFocalPoint = Offset.zero;
|
||||
|
||||
//播放器放缩
|
||||
bool interacting = false;
|
||||
|
||||
// 阅读器限制
|
||||
// Timer? _accessibilityDebounce;
|
||||
// double _lastAnnouncedValue = -1;
|
||||
Offset? _initialFocalPoint;
|
||||
|
||||
bool _pauseDueToPauseUponEnteringBackgroundMode = false;
|
||||
|
||||
@@ -182,9 +174,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
animationController.forward();
|
||||
_animationController.forward();
|
||||
} else {
|
||||
animationController.reverse();
|
||||
_animationController.reverse();
|
||||
}
|
||||
|
||||
if (widget.videoDetailController case final controller?) {
|
||||
@@ -218,9 +210,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
_onControlChanged,
|
||||
);
|
||||
|
||||
transformationController = TransformationController();
|
||||
_transformationController = TransformationController();
|
||||
|
||||
animationController = AnimationController(
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
);
|
||||
@@ -296,6 +288,17 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
_doubleTapGestureRecognizer = DoubleTapGestureRecognizer()
|
||||
..onDoubleTapDown = _onDoubleTapDown;
|
||||
|
||||
_scaleGestureRecognizer = ScaleGestureRecognizer(
|
||||
debugOwner: this,
|
||||
dragStartBehavior: .start,
|
||||
allowedButtonsFilter: (buttons) => buttons == kPrimaryButton,
|
||||
trackpadScrollToScaleFactor: const Offset(
|
||||
0,
|
||||
-1 / kDefaultMouseScrollToScaleFactor,
|
||||
),
|
||||
trackpadScrollCausesScale: false,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -345,14 +348,15 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
_tapGestureRecognizer.dispose();
|
||||
_longPressRecognizer?.dispose();
|
||||
_doubleTapGestureRecognizer.dispose();
|
||||
_scaleGestureRecognizer.dispose();
|
||||
_brightnessListener?.cancel();
|
||||
_controlsListener?.cancel();
|
||||
animationController.dispose();
|
||||
_animationController.dispose();
|
||||
_transformationController.dispose();
|
||||
_removeDmAction();
|
||||
if (PlatformUtils.isMobile) {
|
||||
FlutterVolumeController.removeListener();
|
||||
}
|
||||
transformationController.dispose();
|
||||
_removeDmAction();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -923,7 +927,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
bool get isFullScreen => plPlayerController.isFullScreen.value;
|
||||
|
||||
late final TransformationController transformationController;
|
||||
late final TransformationController _transformationController;
|
||||
|
||||
late ColorScheme colorScheme;
|
||||
late double maxWidth;
|
||||
@@ -935,84 +939,61 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
colorScheme = ColorScheme.of(context);
|
||||
}
|
||||
|
||||
void _onInteractionStart(ScaleStartDetails details) {
|
||||
if (plPlayerController.controlsLock.value) return;
|
||||
// 如果起点太靠上则屏蔽
|
||||
final localFocalPoint = details.localFocalPoint;
|
||||
final dx = localFocalPoint.dx;
|
||||
final dy = localFocalPoint.dy;
|
||||
if (dx < 40 || dy < 40) return;
|
||||
if (dx > maxWidth - 40 || dy > maxHeight - 40) return;
|
||||
if (details.pointerCount > 1) {
|
||||
interacting = true;
|
||||
}
|
||||
initialFocalPoint = localFocalPoint;
|
||||
// if (kDebugMode) {
|
||||
// debugPrint("_initialFocalPoint$_initialFocalPoint");
|
||||
// }
|
||||
void _onPanStart(ScaleStartDetails details) {
|
||||
_gestureType = null;
|
||||
_initialFocalPoint = details.localFocalPoint;
|
||||
}
|
||||
|
||||
void _onInteractionUpdate(ScaleUpdateDetails details) {
|
||||
showRestoreScaleBtn.value =
|
||||
transformationController.value.storage[0] != 1.0;
|
||||
if (interacting || initialFocalPoint == Offset.zero) {
|
||||
return;
|
||||
}
|
||||
Offset cumulativeDelta = details.localFocalPoint - initialFocalPoint;
|
||||
if (details.pointerCount > 1 && cumulativeDelta.distanceSquared < 2.25) {
|
||||
interacting = true;
|
||||
_gestureType = null;
|
||||
return;
|
||||
}
|
||||
|
||||
/// 锁定时禁用
|
||||
if (plPlayerController.controlsLock.value) return;
|
||||
void _onScaleUpdate(double scale) {
|
||||
showRestoreScaleBtn.value = scale != 1.0;
|
||||
}
|
||||
|
||||
void _onPanUpdate(ScaleUpdateDetails details) {
|
||||
if (_gestureType == null) {
|
||||
final cumulativeDelta = details.localFocalPoint - _initialFocalPoint!;
|
||||
if (cumulativeDelta.distanceSquared < 1) return;
|
||||
final dx = cumulativeDelta.dx.abs();
|
||||
final dy = cumulativeDelta.dy.abs();
|
||||
if (dx > 3 * dy) {
|
||||
_gestureType = GestureType.horizontal;
|
||||
_gestureType = .horizontal;
|
||||
} else if (dy > 3 * dx) {
|
||||
if (!plPlayerController.enableSlideVolumeBrightness &&
|
||||
!plPlayerController.enableSlideFS) {
|
||||
return;
|
||||
}
|
||||
|
||||
// _gestureType = 'vertical';
|
||||
|
||||
final double tapPosition = details.localFocalPoint.dx;
|
||||
final double sectionWidth = maxWidth / 3;
|
||||
if (tapPosition < sectionWidth) {
|
||||
if (PlatformUtils.isDesktop ||
|
||||
!plPlayerController.enableSlideVolumeBrightness) {
|
||||
if (!plPlayerController.enableSlideVolumeBrightness) {
|
||||
return;
|
||||
}
|
||||
// 左边区域
|
||||
_gestureType = GestureType.left;
|
||||
if (PlatformUtils.isDesktop) {
|
||||
_gestureType = .right;
|
||||
} else {
|
||||
_gestureType = .left;
|
||||
}
|
||||
} else if (tapPosition < sectionWidth * 2) {
|
||||
if (!plPlayerController.enableSlideFS) {
|
||||
return;
|
||||
}
|
||||
// 全屏
|
||||
_gestureType = GestureType.center;
|
||||
_gestureType = .center;
|
||||
} else {
|
||||
if (!plPlayerController.enableSlideVolumeBrightness) {
|
||||
return;
|
||||
}
|
||||
// 右边区域
|
||||
_gestureType = GestureType.right;
|
||||
_gestureType = .right;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Offset delta = details.focalPointDelta;
|
||||
|
||||
if (_gestureType == GestureType.horizontal) {
|
||||
if (_gestureType == .horizontal) {
|
||||
// live模式下禁用
|
||||
if (plPlayerController.isLive) return;
|
||||
|
||||
@@ -1074,39 +1055,37 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
plPlayerController.cancelSeek != true) {
|
||||
plPlayerController.updatePreviewIndex(newPos ~/ 1000);
|
||||
}
|
||||
} else if (_gestureType == GestureType.left) {
|
||||
} else if (_gestureType == .left) {
|
||||
// 左边区域 👈
|
||||
final double level = maxHeight * 3;
|
||||
final double brightness = (_brightnessValue.value - delta.dy / level)
|
||||
.clamp(0.0, 1.0);
|
||||
setBrightness(brightness);
|
||||
} else if (_gestureType == GestureType.center) {
|
||||
} else if (_gestureType == .center) {
|
||||
// 全屏
|
||||
const double threshold = 2.5; // 滑动阈值
|
||||
double cumulativeDy = details.localFocalPoint.dy - initialFocalPoint.dy;
|
||||
double cumulativeDy = details.localFocalPoint.dy - _initialFocalPoint!.dy;
|
||||
|
||||
void fullScreenTrigger(bool status) {
|
||||
plPlayerController.triggerFullScreen(status: status);
|
||||
}
|
||||
|
||||
if (cumulativeDy > threshold) {
|
||||
_gestureType = GestureType.center_down;
|
||||
_gestureType = .center_down;
|
||||
if (isFullScreen ^ plPlayerController.fullScreenGestureReverse) {
|
||||
fullScreenTrigger(
|
||||
plPlayerController.fullScreenGestureReverse,
|
||||
);
|
||||
}
|
||||
// if (kDebugMode) debugPrint('center_down:$cumulativeDy');
|
||||
} else if (cumulativeDy < -threshold) {
|
||||
_gestureType = GestureType.center_up;
|
||||
_gestureType = .center_up;
|
||||
if (!isFullScreen ^ plPlayerController.fullScreenGestureReverse) {
|
||||
fullScreenTrigger(
|
||||
!plPlayerController.fullScreenGestureReverse,
|
||||
);
|
||||
}
|
||||
// if (kDebugMode) debugPrint('center_up:$cumulativeDy');
|
||||
}
|
||||
} else if (_gestureType == GestureType.right) {
|
||||
} else if (_gestureType == .right) {
|
||||
// 右边区域
|
||||
final double level = maxHeight * 0.5;
|
||||
EasyThrottle.throttle(
|
||||
@@ -1124,7 +1103,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}
|
||||
}
|
||||
|
||||
void _onInteractionEnd(ScaleEndDetails details) {
|
||||
void _onPanEnd(ScaleEndDetails details) {
|
||||
if (Platform.isAndroid &&
|
||||
_gestureType == .left &&
|
||||
plPlayerController.setSystemBrightness) {
|
||||
@@ -1146,8 +1125,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}
|
||||
plPlayerController.onChangedSliderEnd();
|
||||
}
|
||||
interacting = false;
|
||||
initialFocalPoint = Offset.zero;
|
||||
_initialFocalPoint = null;
|
||||
_gestureType = null;
|
||||
}
|
||||
|
||||
@@ -1168,25 +1146,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
plPlayerController.doubleTapFuc(type);
|
||||
}
|
||||
|
||||
void onTapDesktop() {
|
||||
if (plPlayerController.isLive || plPlayerController.controlsLock.value) {
|
||||
return;
|
||||
}
|
||||
plPlayerController.onDoubleTapCenter();
|
||||
}
|
||||
|
||||
void onDoubleTapDesktop() {
|
||||
if (plPlayerController.controlsLock.value) {
|
||||
return;
|
||||
}
|
||||
plPlayerController.triggerFullScreen(status: !isFullScreen);
|
||||
}
|
||||
|
||||
void _onTapUp(TapUpDetails details) {
|
||||
switch (details.kind) {
|
||||
case ui.PointerDeviceKind.mouse when PlatformUtils.isDesktop:
|
||||
onTapDesktop();
|
||||
break;
|
||||
plPlayerController.onDoubleTapCenter();
|
||||
default:
|
||||
if (_suspendedDm == null) {
|
||||
plPlayerController.controls = !plPlayerController.showControls.value;
|
||||
@@ -1195,7 +1158,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
} else {
|
||||
_suspendedDm = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1225,11 +1187,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
void _onDoubleTapDown(TapDownDetails details) {
|
||||
switch (details.kind) {
|
||||
case ui.PointerDeviceKind.mouse when PlatformUtils.isDesktop:
|
||||
onDoubleTapDesktop();
|
||||
break;
|
||||
plPlayerController.triggerFullScreen(status: !isFullScreen);
|
||||
default:
|
||||
onDoubleTapDownMobile(details);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,8 +1207,21 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
plPlayerController.setLongPressStatus(false));
|
||||
late final ImmediateTapGestureRecognizer _tapGestureRecognizer;
|
||||
late final DoubleTapGestureRecognizer _doubleTapGestureRecognizer;
|
||||
late final ScaleGestureRecognizer _scaleGestureRecognizer;
|
||||
|
||||
StreamSubscription<bool>? _danmakuListener;
|
||||
|
||||
static const _kOffsetThreshold = 40.0;
|
||||
bool _isPositionAllowed(Offset offset) {
|
||||
if (offset.dx < _kOffsetThreshold ||
|
||||
offset.dy < _kOffsetThreshold ||
|
||||
offset.dx > maxWidth - _kOffsetThreshold ||
|
||||
offset.dy > maxHeight - _kOffsetThreshold) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void _onPointerDown(PointerDownEvent event) {
|
||||
if (PlatformUtils.isDesktop) {
|
||||
final buttons = event.buttons;
|
||||
@@ -1260,20 +1233,37 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
..controlsLock.value = false
|
||||
..showControls.value = false;
|
||||
}
|
||||
plPlayerController
|
||||
.triggerFullScreen(
|
||||
status: !isFullScreen,
|
||||
inAppFullScreen: isSecondaryBtn,
|
||||
)
|
||||
.whenComplete(() => initialFocalPoint = Offset.zero);
|
||||
plPlayerController.triggerFullScreen(
|
||||
status: !isFullScreen,
|
||||
inAppFullScreen: isSecondaryBtn,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_tapGestureRecognizer.addPointer(event);
|
||||
_doubleTapGestureRecognizer.addPointer(event);
|
||||
if (!plPlayerController.isLive) {
|
||||
longPressRecognizer.addPointer(event);
|
||||
if (_isPositionAllowed(event.localPosition)) {
|
||||
final controlsUnlock = !plPlayerController.controlsLock.value;
|
||||
if (PlatformUtils.isMobile) {
|
||||
_tapGestureRecognizer.addPointer(event);
|
||||
if (controlsUnlock) {
|
||||
if (!plPlayerController.isLive) {
|
||||
_doubleTapGestureRecognizer.addPointer(event);
|
||||
longPressRecognizer.addPointer(event);
|
||||
}
|
||||
_scaleGestureRecognizer.addPointer(event);
|
||||
}
|
||||
} else {
|
||||
if (controlsUnlock) {
|
||||
if (!plPlayerController.isLive) {
|
||||
_tapGestureRecognizer.addPointer(event);
|
||||
}
|
||||
_doubleTapGestureRecognizer.addPointer(event);
|
||||
if (!plPlayerController.isLive) {
|
||||
longPressRecognizer.addPointer(event);
|
||||
}
|
||||
_scaleGestureRecognizer.addPointer(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1285,17 +1275,17 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
final dx = pan.dx.abs();
|
||||
final dy = pan.dy.abs();
|
||||
if (dx > 3 * dy) {
|
||||
_gestureType = GestureType.horizontal;
|
||||
_gestureType = .horizontal;
|
||||
} else if (dy > 3 * dx) {
|
||||
_gestureType = GestureType.right;
|
||||
_gestureType = .right;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_gestureType == GestureType.horizontal) {
|
||||
if (_gestureType == .horizontal) {
|
||||
if (plPlayerController.isLive) return;
|
||||
|
||||
Offset delta = event.localPanDelta;
|
||||
final delta = event.localPanDelta;
|
||||
final int curSliderPosition =
|
||||
plPlayerController.sliderPosition.inMilliseconds;
|
||||
final int newPos =
|
||||
@@ -1317,7 +1307,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
plPlayerController.cancelSeek != true) {
|
||||
plPlayerController.updatePreviewIndex(newPos ~/ 1000);
|
||||
}
|
||||
} else if (_gestureType == GestureType.right) {
|
||||
} else if (_gestureType == .right) {
|
||||
if (!plPlayerController.enableSlideVolumeBrightness) {
|
||||
return;
|
||||
}
|
||||
@@ -1339,6 +1329,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}
|
||||
|
||||
void _onPointerPanZoomEnd(PointerPanZoomEndEvent event) {
|
||||
plPlayerController.showPreview.value = false;
|
||||
if (plPlayerController.isSliderMoving.value) {
|
||||
plPlayerController
|
||||
..seekTo(plPlayerController.sliderPosition, isSeek: false)
|
||||
..onChangedSliderEnd();
|
||||
}
|
||||
_gestureType = null;
|
||||
}
|
||||
|
||||
@@ -1619,7 +1615,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
children: [
|
||||
AppBarAni(
|
||||
isTop: true,
|
||||
controller: animationController,
|
||||
controller: _animationController,
|
||||
isFullScreen: isFullScreen,
|
||||
removeSafeArea: plPlayerController.removeSafeArea,
|
||||
child: plPlayerController.isDesktopPip
|
||||
@@ -1632,7 +1628,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
AppBarAni(
|
||||
isTop: false,
|
||||
controller: animationController,
|
||||
controller: _animationController,
|
||||
isFullScreen: isFullScreen,
|
||||
removeSafeArea: plPlayerController.removeSafeArea,
|
||||
child:
|
||||
@@ -1697,12 +1693,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
);
|
||||
final anim = animController.drive(
|
||||
Matrix4Tween(
|
||||
begin: transformationController.value,
|
||||
begin: _transformationController.value,
|
||||
end: Matrix4.identity(),
|
||||
).chain(CurveTween(curve: Curves.easeOut)),
|
||||
);
|
||||
void listener() {
|
||||
transformationController.value = anim.value;
|
||||
_transformationController.value = anim.value;
|
||||
}
|
||||
|
||||
animController.addListener(listener);
|
||||
@@ -2035,7 +2031,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
Widget get _videoWidget {
|
||||
return Container(
|
||||
clipBehavior: Clip.none,
|
||||
clipBehavior: .none,
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
color: widget.fill,
|
||||
@@ -2046,24 +2042,19 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
onPointerPanZoomUpdate: _onPointerPanZoomUpdate,
|
||||
onPointerPanZoomEnd: _onPointerPanZoomEnd,
|
||||
onPointerDown: _onPointerDown,
|
||||
onInteractionStart: _onInteractionStart,
|
||||
onInteractionUpdate: _onInteractionUpdate,
|
||||
onInteractionEnd: _onInteractionEnd,
|
||||
onPanStart: _onPanStart,
|
||||
onPanUpdate: _onPanUpdate,
|
||||
onPanEnd: _onPanEnd,
|
||||
onScaleUpdate: _onScaleUpdate,
|
||||
scaleGestureRecognizer: _scaleGestureRecognizer,
|
||||
panEnabled: false,
|
||||
minScale: plPlayerController.enableShrinkVideoSize ? 0.75 : 1,
|
||||
maxScale: 2.0,
|
||||
boundaryMargin: plPlayerController.enableShrinkVideoSize
|
||||
? const EdgeInsets.all(double.infinity)
|
||||
: EdgeInsets.zero,
|
||||
panAxis: PanAxis.aligned,
|
||||
transformationController: transformationController,
|
||||
onTranslate: () {
|
||||
final storage = transformationController.value.storage;
|
||||
showRestoreScaleBtn.value =
|
||||
storage[12].abs() > 2.0 ||
|
||||
storage[13].abs() > 2.0 ||
|
||||
storage[0] != 1.0;
|
||||
},
|
||||
? const .all(double.infinity)
|
||||
: .zero,
|
||||
panAxis: .aligned,
|
||||
transformationController: _transformationController,
|
||||
childKey: _videoKey,
|
||||
child: RepaintBoundary(
|
||||
key: _videoKey,
|
||||
|
||||
Reference in New Issue
Block a user