fix: broken video player focus

close #393
This commit is contained in:
edde746
2026-02-06 21:10:31 +01:00
parent ff75cf8ddb
commit 09337f50ee
2 changed files with 32 additions and 1 deletions
+21 -1
View File
@@ -46,6 +46,7 @@ import '../utils/video_player_navigation.dart';
import '../widgets/video_controls/video_controls.dart';
import '../focus/focusable_wrapper.dart';
import '../focus/input_mode_tracker.dart';
import '../focus/dpad_navigator.dart';
import '../focus/key_event_utils.dart';
import '../i18n/strings.g.dart';
import '../watch_together/providers/watch_together_provider.dart';
@@ -1726,7 +1727,26 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
focusNode: _screenFocusNode,
autofocus: isCurrentRoute,
canRequestFocus: isCurrentRoute,
onKeyEvent: (node, event) => isCurrentRoute ? KeyEventResult.handled : KeyEventResult.ignored,
onKeyEvent: (node, event) {
if (!isCurrentRoute) return KeyEventResult.ignored;
// Safety net: if this screen-level node itself has primary focus
// (no descendant focused, e.g. after controls auto-hide), self-heal.
if (node.hasPrimaryFocus) {
// Handle BACK immediately so the user is never stuck.
final backResult = handleBackKeyAction(event, _handleBackButton);
if (backResult != KeyEventResult.ignored) return backResult;
// Redirect focus to the first traversable descendant (video controls)
// and show controls immediately so the first key press isn't swallowed.
if (event.isActionable) {
_controlsVisible.value = true;
final descendants = node.traversalDescendants;
if (descendants.isNotEmpty) {
descendants.first.requestFocus();
}
}
}
return KeyEventResult.handled;
},
child: _isPlayerInitialized && player != null ? _buildVideoPlayer(context) : _buildLoadingSpinner(),
);
}
@@ -260,6 +260,8 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
HardwareKeyboard.instance.addHandler(_handleGlobalKeyEvent);
// Listen for first frame to start auto-hide timer
widget.hasFirstFrame?.addListener(_onFirstFrameReady);
// Listen for external requests to show controls (e.g. screen-level focus recovery)
widget.controlsVisible?.addListener(_onControlsVisibleExternal);
}
/// Called when hasFirstFrame changes - start auto-hide timer when first frame is ready
@@ -269,6 +271,14 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
}
}
/// Called when controlsVisible is set externally (e.g. screen-level focus recovery
/// after controls auto-hide ejects focus on Android TV).
void _onControlsVisibleExternal() {
if (widget.controlsVisible?.value == true && !_showControls && mounted) {
_showControlsWithFocus();
}
}
/// Focus play/pause button if we're in keyboard navigation mode (desktop/TV only)
void _focusPlayPauseIfKeyboardMode() {
if (!mounted) return;
@@ -515,6 +525,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
@override
void dispose() {
HardwareKeyboard.instance.removeHandler(_handleGlobalKeyEvent);
widget.controlsVisible?.removeListener(_onControlsVisibleExternal);
widget.hasFirstFrame?.removeListener(_onFirstFrameReady);
_hideTimer?.cancel();
_feedbackTimer?.cancel();