feat(lyrics): keep the screen awake while viewing lyrics

This commit is contained in:
zarzet committed 2026-09-30 20:21:21 +07:00
1 parent a1cec6de51
commit 8aa8d598d8
14 files changed
+276

No files matched your search

+78
View File
@@ -0,0 +1,78 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/services/platform_bridge.dart';
import 'package:spotiflac_android/utils/logger.dart';
final _log = AppLogger('LyricsScreenAwake');
/// Holds only the visible lyrics screen awake, never background audio playback.
class LyricsScreenAwake extends ConsumerStatefulWidget {
const LyricsScreenAwake({
required this.visible,
required this.child,
super.key,
});
final bool visible;
final Widget child;
@override
ConsumerState<LyricsScreenAwake> createState() => _LyricsScreenAwakeState();
}
class _LyricsScreenAwakeState extends ConsumerState<LyricsScreenAwake>
with WidgetsBindingObserver {
bool _wanted = false;
bool _requested = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
void _update({bool force = false}) {
final lifecycle = WidgetsBinding.instance.lifecycleState;
final enabled =
_wanted &&
(lifecycle == null || lifecycle == AppLifecycleState.resumed);
if (!force && enabled == _requested) return;
_requested = enabled;
unawaited(_setAwake(enabled));
}
Future<void> _setAwake(bool enabled) async {
try {
await PlatformBridge.setScreenAwake(enabled);
} catch (error) {
_log.w('Could not update screen timeout: $error');
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// Reapply after resuming: Android may have recreated the Activity/window.
_update(force: state == AppLifecycleState.resumed);
}
@override
Widget build(BuildContext context) {
final enabled = ref.watch(
settingsProvider.select((settings) => settings.keepScreenOnLyrics),
);
_wanted =
widget.visible && enabled && (ModalRoute.isCurrentOf(context) ?? true);
_update();
return widget.child;
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
if (_requested) unawaited(_setAwake(false));
super.dispose();
}
}