fix: hide playback controls faster on desktop

close #391
This commit is contained in:
edde746
2026-02-09 06:19:33 +01:00
parent d313ccbc84
commit 7ec019b12e
+49 -20
View File
@@ -339,13 +339,13 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
});
}
/// Listen to playback state changes to manage auto-hide timer on iOS/mobile
/// Listen to playback state changes to manage auto-hide timer
void _listenToPlayingState() {
_playingSubscription = widget.player.streams.playing.listen((isPlaying) {
if (isPlaying && _showControls) {
_startHideTimer();
} else if (!isPlaying) {
_hideTimer?.cancel();
} else if (!isPlaying && _showControls) {
_startPausedHideTimer();
}
});
}
@@ -606,6 +606,32 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
// Lag during resize is now handled in native code (glViewport + resize signal handler)
}
/// Controls hide delay: 5s on mobile/TV/keyboard-nav, 3s on desktop with mouse.
Duration get _hideDelay {
final isMobile = PlatformDetector.isMobile(context) && !PlatformDetector.isTV();
if (isMobile || PlatformDetector.isTV() || _videoPlayerNavigationEnabled) {
return const Duration(seconds: 5);
}
return const Duration(seconds: 3);
}
/// Shared hide logic: hides controls, notifies parent, updates traffic lights, restores focus.
void _hideControls() {
if (!mounted || !_showControls) return;
setState(() {
_showControls = false;
});
widget.controlsVisible?.value = false;
if (Platform.isMacOS) {
_updateTrafficLightVisibility();
}
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted && !_focusNode.hasFocus) {
_focusNode.requestFocus();
}
});
}
void _startHideTimer() {
_hideTimer?.cancel();
@@ -615,31 +641,24 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
// Only auto-hide if playing
if (widget.player.state.playing) {
_hideTimer = Timer(const Duration(seconds: 3), () {
_hideTimer = Timer(_hideDelay, () {
// Also check hasFirstFrame in callback (in case it changed)
final stillLoading = !(widget.hasFirstFrame?.value ?? true);
if (mounted && widget.player.state.playing && !stillLoading) {
setState(() {
_showControls = false;
});
// Notify parent of visibility change (for popup positioning)
widget.controlsVisible?.value = false;
// Hide traffic lights on macOS when controls auto-hide
if (Platform.isMacOS) {
_updateTrafficLightVisibility();
}
// Restore focus to the main node so keyboard shortcuts keep working
// after FocusScope(canRequestFocus: false) ejects child focus.
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted && !_focusNode.hasFocus) {
_focusNode.requestFocus();
}
});
_hideControls();
}
});
}
}
/// Auto-hide controls after pause (does not check playing state in callback).
void _startPausedHideTimer() {
_hideTimer?.cancel();
_hideTimer = Timer(_hideDelay, () {
_hideControls();
});
}
/// Restart the hide timer on user interaction (if video is playing)
void _restartHideTimerIfPlaying() {
if (widget.player.state.playing) {
@@ -647,6 +666,15 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
}
}
/// Hide controls immediately when the mouse leaves the player area (desktop only).
void _hideControlsFromPointerExit() {
final isMobile = PlatformDetector.isMobile(context) && !PlatformDetector.isTV();
if (isMobile) return;
_hideTimer?.cancel();
_hideControls();
}
/// Show controls in response to pointer activity (mouse/trackpad movement).
void _showControlsFromPointerActivity() {
if (!_showControls) {
@@ -1533,6 +1561,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
child: MouseRegion(
cursor: _showControls ? SystemMouseCursors.basic : SystemMouseCursors.none,
onHover: (_) => _showControlsFromPointerActivity(),
onExit: (_) => _hideControlsFromPointerExit(),
child: Stack(
children: [
// Keep-alive: 1px widget that continuously repaints to prevent