From 2278af8d8380012e6037af1d288986ff2daf87a7 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Sat, 14 Feb 2026 11:46:17 +0100 Subject: [PATCH] fix: exit video player when sleep timer completes close #456 --- lib/screens/video_player_screen.dart | 8 ++++++++ lib/services/sleep_timer_service.dart | 5 +++++ .../video_controls/widgets/sleep_timer_duration_list.dart | 5 ----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index c7ba1403..8293eb1c 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -33,6 +33,7 @@ import '../services/playback_initialization_service.dart'; import '../services/playback_progress_tracker.dart'; import '../services/offline_watch_sync_service.dart'; import '../services/settings_service.dart'; +import '../services/sleep_timer_service.dart'; import '../services/track_selection_service.dart'; import '../services/video_filter_manager.dart'; import '../services/video_pip_manager.dart'; @@ -106,6 +107,7 @@ class VideoPlayerScreenState extends State with WidgetsBindin StreamSubscription? _positionSubscription; StreamSubscription? _playbackRestartSubscription; StreamSubscription? _backendSwitchedSubscription; + StreamSubscription? _sleepTimerSubscription; bool _isReplacingWithVideo = false; // Flag to skip orientation restoration during video-to-video navigation bool _isDisposingForNavigation = false; bool _waitingForExternalSubsTrackSelection = false; @@ -219,6 +221,11 @@ class VideoPlayerScreenState extends State with WidgetsBindin // Wire companion remote playback callbacks _setupCompanionRemoteCallbacks(); + // Exit the player when the sleep timer completes so the device can auto-lock + _sleepTimerSubscription = SleepTimerService().onCompleted.listen((_) { + if (mounted) _handleBackButton(); + }); + // Initialize player asynchronously with buffer size from settings _initializePlayer(); } @@ -1374,6 +1381,7 @@ class VideoPlayerScreenState extends State with WidgetsBindin _positionSubscription?.cancel(); _playbackRestartSubscription?.cancel(); _backendSwitchedSubscription?.cancel(); + _sleepTimerSubscription?.cancel(); // Cancel auto-play timer _autoPlayTimer?.cancel(); diff --git a/lib/services/sleep_timer_service.dart b/lib/services/sleep_timer_service.dart index a9c8e698..94db244a 100644 --- a/lib/services/sleep_timer_service.dart +++ b/lib/services/sleep_timer_service.dart @@ -13,6 +13,10 @@ class SleepTimerService extends ChangeNotifier { DateTime? _endTime; Duration? _duration; VoidCallback? _onTimerComplete; + final StreamController _completedController = StreamController.broadcast(); + + /// Emits when the sleep timer completes (not when cancelled) + Stream get onCompleted => _completedController.stream; /// Whether a timer is currently active bool get isActive => _timer != null && _timer!.isActive; @@ -91,6 +95,7 @@ class SleepTimerService extends ChangeNotifier { appLogger.e('Error executing sleep timer callback', error: e); } } + _completedController.add(null); } @override diff --git a/lib/widgets/video_controls/widgets/sleep_timer_duration_list.dart b/lib/widgets/video_controls/widgets/sleep_timer_duration_list.dart index dd6dfac8..de5d9203 100644 --- a/lib/widgets/video_controls/widgets/sleep_timer_duration_list.dart +++ b/lib/widgets/video_controls/widgets/sleep_timer_duration_list.dart @@ -44,11 +44,6 @@ class SleepTimerDurationList extends StatelessWidget { sleepTimer.startTimer(Duration(minutes: minutes), () { // Pause playback when timer completes player.pause(); - - // Show a snackbar notification - if (context.mounted) { - showSuccessSnackBar(context, t.videoControls.sleepTimerCompleted); - } }); Navigator.pop(context);