From 3bfc24bf9b4e6b3dd481796c5a6632d6c94fb7e5 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:32:51 +0100 Subject: [PATCH] feat: persist ambient lighting and make it mutually exclusive with shaders close #499 --- lib/screens/video_player_screen.dart | 46 +++++++++++++++++++ lib/services/settings_service.dart | 11 +++++ .../sheets/video_settings_sheet.dart | 4 ++ 3 files changed, 61 insertions(+) diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index 5f81a2d2..f1c6c25b 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -40,6 +40,7 @@ import '../services/ambient_lighting_service.dart'; import '../services/video_filter_manager.dart'; import '../services/video_pip_manager.dart'; import '../services/pip_service.dart'; +import '../models/shader_preset.dart'; import '../services/shader_service.dart'; import '../providers/shader_provider.dart'; import '../providers/user_profile_provider.dart'; @@ -1032,6 +1033,7 @@ class VideoPlayerScreenState extends State with WidgetsBindin _videoFilterManager?.ambientLightingService = _ambientLightingService; await _applySavedShaderPreset(); + await _restoreAmbientLighting(); } } @@ -1147,6 +1149,39 @@ class VideoPlayerScreenState extends State with WidgetsBindin } } + /// Restore ambient lighting from persisted setting + Future _restoreAmbientLighting() async { + final settings = await SettingsService.getInstance(); + if (!settings.getAmbientLighting()) return; + + final ambientLighting = _ambientLightingService; + if (ambientLighting == null || !ambientLighting.isSupported) return; + + // Same enable logic as _toggleAmbientLighting + final dwidth = await player?.getProperty('dwidth'); + final dheight = await player?.getProperty('dheight'); + if (dwidth == null || dheight == null) return; + final w = double.tryParse(dwidth); + final h = double.tryParse(dheight); + if (w == null || h == null || h == 0) return; + final videoAspect = w / h; + + final playerSize = _videoFilterManager?.playerSize; + if (playerSize == null || playerSize.height == 0) return; + final outputAspect = playerSize.width / playerSize.height; + + // Clear shaders — ambient lighting and shaders are mutually exclusive + final shaderProvider = context.read(); + if (shaderProvider.isShaderEnabled) { + await _shaderService!.applyPreset(ShaderPreset.none); + shaderProvider.setCurrentPreset(ShaderPreset.none); + } + + _videoFilterManager?.resetToContain(); + await ambientLighting.enable(videoAspect, outputAspect); + if (mounted) setState(() {}); + } + /// Cycle through BoxFit modes: contain → cover → fill → contain (for button) void _cycleBoxFitMode() { // Disable ambient lighting when switching boxfit modes @@ -1190,12 +1225,23 @@ class VideoPlayerScreenState extends State with WidgetsBindin if (playerSize == null || playerSize.height == 0) return; final outputAspect = playerSize.width / playerSize.height; + // Clear shaders — ambient lighting and shaders are mutually exclusive + final shaderProvider = context.read(); + if (shaderProvider.isShaderEnabled) { + await _shaderService!.applyPreset(ShaderPreset.none); + shaderProvider.setCurrentPreset(ShaderPreset.none); + } + // Force contain mode when enabling ambient lighting _videoFilterManager?.resetToContain(); await ambientLighting.enable(videoAspect, outputAspect); } + // Persist ambient lighting state + final settings = await SettingsService.getInstance(); + settings.setAmbientLighting(ambientLighting.isEnabled); + setState(() {}); } diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index 0167a4fa..16f5671f 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -75,6 +75,7 @@ class SettingsService extends BaseSharedPreferencesService { static const String _keySelectedExternalPlayer = 'selected_external_player'; static const String _keyCustomExternalPlayers = 'custom_external_players'; static const String _keyConfirmExitOnBack = 'confirm_exit_on_back'; + static const String _keyAmbientLighting = 'ambient_lighting'; SettingsService._(); @@ -1117,6 +1118,15 @@ class SettingsService extends BaseSharedPreferencesService { return prefs.getBool(_keyConfirmExitOnBack) ?? true; // Default: enabled } + // Ambient Lighting + Future setAmbientLighting(bool enabled) async { + await prefs.setBool(_keyAmbientLighting, enabled); + } + + bool getAmbientLighting() { + return prefs.getBool(_keyAmbientLighting) ?? false; + } + // Reset all settings to defaults Future resetAllSettings() async { await Future.wait([ @@ -1171,6 +1181,7 @@ class SettingsService extends BaseSharedPreferencesService { prefs.remove(_keySelectedExternalPlayer), prefs.remove(_keyCustomExternalPlayers), prefs.remove(_keyConfirmExitOnBack), + prefs.remove(_keyAmbientLighting), ]); } diff --git a/lib/widgets/video_controls/sheets/video_settings_sheet.dart b/lib/widgets/video_controls/sheets/video_settings_sheet.dart index 6453dc5c..ab194c64 100644 --- a/lib/widgets/video_controls/sheets/video_settings_sheet.dart +++ b/lib/widgets/video_controls/sheets/video_settings_sheet.dart @@ -576,6 +576,10 @@ class _VideoSettingsSheetState extends State { : null, trailing: isSelected ? const AppIcon(Symbols.check_rounded, fill: 1, color: Colors.amber) : null, onTap: () async { + // Disable ambient lighting when selecting a shader + if (preset.type != ShaderPresetType.none && widget.isAmbientLightingEnabled) { + widget.onToggleAmbientLighting?.call(); + } await widget.shaderService!.applyPreset(preset); await shaderProvider.setPreset(preset); widget.onShaderChanged?.call();