Files
PiliPlus/lib/pages/video/widgets/player_focus.dart
bggRGjQaUbCoE 340a933e70 fix #1648
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-10-20 10:23:13 +08:00

276 lines
8.6 KiB
Dart

import 'dart:async';
import 'dart:math' as math;
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart'
show KeyDownEvent, KeyUpEvent, LogicalKeyboardKey, HardwareKeyboard;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
class PlayerFocus extends StatelessWidget {
const PlayerFocus({
super.key,
required this.child,
required this.plPlayerController,
this.introController,
required this.onSendDanmaku,
this.canPlay,
this.onSkipSegment,
});
final Widget child;
final PlPlayerController plPlayerController;
final CommonIntroController? introController;
final VoidCallback onSendDanmaku;
final bool Function()? canPlay;
final bool Function()? onSkipSegment;
static bool _shouldHandle(LogicalKeyboardKey logicalKey) {
return logicalKey == LogicalKeyboardKey.tab ||
logicalKey == LogicalKeyboardKey.arrowLeft ||
logicalKey == LogicalKeyboardKey.arrowRight ||
logicalKey == LogicalKeyboardKey.arrowUp ||
logicalKey == LogicalKeyboardKey.arrowDown;
}
@override
Widget build(BuildContext context) {
return Focus(
autofocus: true,
onKeyEvent: (node, event) {
final handled = _handleKey(event);
if (handled || _shouldHandle(event.logicalKey)) {
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
},
child: child,
);
}
bool get isFullScreen => plPlayerController.isFullScreen.value;
bool get hasPlayer => plPlayerController.videoPlayerController != null;
void _setVolume({required bool isIncrease}) {
final volume = isIncrease
? math.min(1.0, plPlayerController.volume.value + 0.1)
: math.max(0.0, plPlayerController.volume.value - 0.1);
plPlayerController.setVolume(volume);
}
void _updateVolume(KeyEvent event, {required bool isIncrease}) {
if (event is KeyDownEvent) {
if (hasPlayer) {
plPlayerController
..cancelLongPressTimer()
..longPressTimer ??= Timer.periodic(
const Duration(milliseconds: 150),
(_) => _setVolume(isIncrease: isIncrease),
);
}
} else if (event is KeyUpEvent) {
if (plPlayerController.longPressTimer?.tick == 0 && hasPlayer) {
_setVolume(isIncrease: isIncrease);
}
plPlayerController.cancelLongPressTimer();
}
}
bool _handleKey(KeyEvent event) {
final key = event.logicalKey;
final isKeyQ = key == LogicalKeyboardKey.keyQ;
if (isKeyQ || key == LogicalKeyboardKey.keyR) {
if (HardwareKeyboard.instance.isMetaPressed) {
return true;
}
if (!plPlayerController.isLive) {
if (event is KeyDownEvent) {
introController!.onStartTriple();
} else if (event is KeyUpEvent) {
introController!.onCancelTriple(isKeyQ);
}
}
return true;
}
final isArrowUp = key == LogicalKeyboardKey.arrowUp;
if (isArrowUp || key == LogicalKeyboardKey.arrowDown) {
_updateVolume(event, isIncrease: isArrowUp);
return true;
}
if (key == LogicalKeyboardKey.arrowRight) {
if (!plPlayerController.isLive) {
if (event is KeyDownEvent) {
if (hasPlayer && !plPlayerController.longPressStatus.value) {
plPlayerController
..cancelLongPressTimer()
..longPressTimer ??= Timer(
const Duration(milliseconds: 200),
() => plPlayerController
..cancelLongPressTimer()
..setLongPressStatus(true),
);
}
} else if (event is KeyUpEvent) {
plPlayerController.cancelLongPressTimer();
if (hasPlayer) {
if (plPlayerController.longPressStatus.value) {
plPlayerController.setLongPressStatus(false);
} else {
plPlayerController.onForward(
plPlayerController.fastForBackwardDuration,
);
}
}
}
}
return true;
}
if (event is KeyDownEvent) {
final isDigit1 = key == LogicalKeyboardKey.digit1;
if (isDigit1 || key == LogicalKeyboardKey.digit2) {
if (HardwareKeyboard.instance.isShiftPressed && hasPlayer) {
final speed = isDigit1 ? 1.0 : 2.0;
if (speed != plPlayerController.playbackSpeed) {
plPlayerController.setPlaybackSpeed(speed);
}
SmartDialog.showToast('${speed}x播放');
}
return true;
}
switch (key) {
case LogicalKeyboardKey.space:
if (plPlayerController.isLive || canPlay!()) {
if (hasPlayer) {
plPlayerController.onDoubleTapCenter();
}
}
return true;
case LogicalKeyboardKey.keyF:
plPlayerController
..triggerFullScreen(
status: !isFullScreen,
inAppFullScreen: HardwareKeyboard.instance.isShiftPressed,
)
..controlsLock.value = false;
return true;
case LogicalKeyboardKey.keyD:
final newVal = !plPlayerController.enableShowDanmaku.value;
plPlayerController.enableShowDanmaku.value = newVal;
if (!plPlayerController.tempPlayerConf) {
GStorage.setting.put(
plPlayerController.isLive
? SettingBoxKey.enableShowLiveDanmaku
: SettingBoxKey.enableShowDanmaku,
newVal,
);
}
return true;
case LogicalKeyboardKey.keyP:
if (Utils.isDesktop && hasPlayer) {
plPlayerController
..toggleDesktopPip()
..controlsLock.value = false;
}
return true;
case LogicalKeyboardKey.keyM:
if (hasPlayer) {
final isMuted = !plPlayerController.isMuted;
plPlayerController.videoPlayerController!.setVolume(
isMuted ? 0 : plPlayerController.volume.value * 100,
);
plPlayerController.isMuted = isMuted;
SmartDialog.showToast('${isMuted ? '' : '取消'}静音');
}
return true;
case LogicalKeyboardKey.keyS:
if (hasPlayer && isFullScreen) {
plPlayerController.takeScreenshot();
}
return true;
case LogicalKeyboardKey.enter:
if (onSkipSegment?.call() ?? false) {
return true;
}
onSendDanmaku();
return true;
}
if (!plPlayerController.isLive) {
switch (key) {
case LogicalKeyboardKey.arrowLeft:
if (hasPlayer) {
plPlayerController.onBackward(
plPlayerController.fastForBackwardDuration,
);
}
return true;
case LogicalKeyboardKey.keyW:
if (HardwareKeyboard.instance.isMetaPressed) {
return true;
}
introController?.actionCoinVideo();
return true;
case LogicalKeyboardKey.keyE:
introController?.actionFavVideo(isQuick: true);
return true;
case LogicalKeyboardKey.keyT || LogicalKeyboardKey.keyV:
introController?.viewLater();
return true;
case LogicalKeyboardKey.keyG:
if (introController case UgcIntroController ugcCtr) {
ugcCtr.actionRelationMod(Get.context!);
}
return true;
case LogicalKeyboardKey.keyL:
if (isFullScreen || plPlayerController.isDesktopPip) {
plPlayerController.onLockControl(
!plPlayerController.controlsLock.value,
);
}
return true;
case LogicalKeyboardKey.bracketLeft:
if (introController case final introController?) {
if (!introController.prevPlay()) {
SmartDialog.showToast('已经是第一集了');
}
}
return true;
case LogicalKeyboardKey.bracketRight:
if (introController case final introController?) {
if (!introController.nextPlay()) {
SmartDialog.showToast('已经是最后一集了');
}
}
return true;
}
}
}
return false;
}
}