fix: auto hide controls on mobile

close #129
This commit is contained in:
edde746
2025-11-25 04:03:23 +01:00
parent 516bf3a689
commit a7f1c8a13c
+65 -33
View File
@@ -1,4 +1,4 @@
import 'dart:async';
import 'dart:async' show StreamSubscription, Timer;
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
@@ -112,6 +112,8 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
PlexMarker? _currentMarker;
List<PlexMarker> _markers = [];
bool _markersLoaded = false;
// Playback state subscription for auto-hide timer
StreamSubscription<bool>? _playingSubscription;
@override
void initState() {
@@ -123,6 +125,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
_startHideTimer();
_initKeyboardService();
_listenToPosition();
_listenToPlayingState();
// Add lifecycle observer to reload settings when app resumes
WidgetsBinding.instance.addObserver(this);
// Add window listener for tracking fullscreen state (for button icon)
@@ -159,6 +162,17 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
});
}
/// Listen to playback state changes to manage auto-hide timer on iOS/mobile
void _listenToPlayingState() {
_playingSubscription = widget.player.stream.playing.listen((isPlaying) {
if (isPlaying && _showControls) {
_startHideTimer();
} else if (!isPlaying) {
_hideTimer?.cancel();
}
});
}
void _skipMarker() {
if (_currentMarker != null) {
widget.player.seek(_currentMarker!.endTime);
@@ -221,6 +235,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
_hideTimer?.cancel();
_feedbackTimer?.cancel();
_seekThrottleTimer?.cancel();
_playingSubscription?.cancel();
_focusNode.dispose();
// Remove lifecycle observer
WidgetsBinding.instance.removeObserver(this);
@@ -295,6 +310,13 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
}
}
/// Restart the hide timer on user interaction (if video is playing)
void _restartHideTimerIfPlaying() {
if (widget.player.state.playing) {
_startHideTimer();
}
}
void _toggleControls() {
setState(() {
_showControls = !_showControls;
@@ -635,40 +657,50 @@ class _PlexVideoControlsState extends State<PlexVideoControls>
),
),
child: isMobile
? MobileVideoControls(
player: widget.player,
metadata: widget.metadata,
chapters: _chapters,
chaptersLoaded: _chaptersLoaded,
seekTimeSmall: _seekTimeSmall,
trackChapterControls:
_buildTrackChapterControlsWidget(),
onSeek: _throttledSeek,
onSeekEnd: _finalizeSeek,
onPlayPause:
() {}, // Not used, handled internally
onCancelAutoHide: () => _hideTimer?.cancel(),
onStartAutoHide: _startHideTimer,
)
: DesktopVideoControls(
player: widget.player,
metadata: widget.metadata,
onNext: widget.onNext,
onPrevious: widget.onPrevious,
chapters: _chapters,
chaptersLoaded: _chaptersLoaded,
seekTimeSmall: _seekTimeSmall,
volumeControl: VolumeControl(
? Listener(
behavior: HitTestBehavior.translucent,
onPointerDown: (_) =>
_restartHideTimerIfPlaying(),
child: MobileVideoControls(
player: widget.player,
metadata: widget.metadata,
chapters: _chapters,
chaptersLoaded: _chaptersLoaded,
seekTimeSmall: _seekTimeSmall,
trackChapterControls:
_buildTrackChapterControlsWidget(),
onSeek: _throttledSeek,
onSeekEnd: _finalizeSeek,
onPlayPause:
() {}, // Not used, handled internally
onCancelAutoHide: () => _hideTimer?.cancel(),
onStartAutoHide: _startHideTimer,
),
)
: Listener(
behavior: HitTestBehavior.translucent,
onPointerDown: (_) =>
_restartHideTimerIfPlaying(),
child: DesktopVideoControls(
player: widget.player,
metadata: widget.metadata,
onNext: widget.onNext,
onPrevious: widget.onPrevious,
chapters: _chapters,
chaptersLoaded: _chaptersLoaded,
seekTimeSmall: _seekTimeSmall,
volumeControl: VolumeControl(
player: widget.player,
),
trackChapterControls:
_buildTrackChapterControlsWidget(),
onSeekToPreviousChapter: _seekToPreviousChapter,
onSeekToNextChapter: _seekToNextChapter,
onSeek: _throttledSeek,
onSeekEnd: _finalizeSeek,
getReplayIcon: getReplayIcon,
getForwardIcon: getForwardIcon,
),
trackChapterControls:
_buildTrackChapterControlsWidget(),
onSeekToPreviousChapter: _seekToPreviousChapter,
onSeekToNextChapter: _seekToNextChapter,
onSeek: _throttledSeek,
onSeekEnd: _finalizeSeek,
getReplayIcon: getReplayIcon,
getForwardIcon: getForwardIcon,
),
),
),