refactor(settings): share preference binding lifecycle

This commit is contained in:
edde746
2026-07-12 08:42:25 +02:00
parent c81a1f9a97
commit 352aa04d3e
5 changed files with 228 additions and 90 deletions
+14 -30
View File
@@ -1,15 +1,16 @@
import 'dart:async' show unawaited;
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import '../mixins/disposable_change_notifier_mixin.dart';
import '../models/shader_preset.dart';
import '../services/settings_binding_owner.dart';
import '../services/settings_service.dart';
import '../services/shader_asset_loader.dart';
class ShaderProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
SettingsService? _settingsService;
ValueNotifier<String>? _savedPresetListenable;
ValueNotifier<List<Map<String, dynamic>>>? _customPresetsListenable;
late final SettingsBindingOwner _settingsBinding;
ShaderPreset _savedPreset = ShaderPreset.none;
ShaderPreset _currentPreset = ShaderPreset.none;
@@ -17,30 +18,14 @@ class ShaderProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
bool _initialized = false;
ShaderProvider() {
_initialize();
_settingsBinding = SettingsBindingOwner(
prefs: [SettingsService.globalShaderPreset, SettingsService.customShaderPresets],
onRefresh: _syncFromSettings,
);
unawaited(_settingsBinding.bind());
}
Future<void> _initialize() async {
final service = await SettingsService.getInstance();
if (_settingsService == service && _savedPresetListenable != null && _customPresetsListenable != null) {
_syncFromSettings();
return;
}
_savedPresetListenable?.removeListener(_onSettingsChanged);
_customPresetsListenable?.removeListener(_onSettingsChanged);
_settingsService = service;
_savedPresetListenable = service.listenable(SettingsService.globalShaderPreset)..addListener(_onSettingsChanged);
_customPresetsListenable = service.listenable(SettingsService.customShaderPresets)..addListener(_onSettingsChanged);
_syncFromSettings();
}
void _onSettingsChanged() => _syncFromSettings();
void _syncFromSettings() {
final service = _settingsService;
if (service == null) return;
void _syncFromSettings(SettingsService service) {
final customData = service.read(SettingsService.customShaderPresets);
final customPresets = customData.map((json) => ShaderPreset.fromJson(json)).toList();
_customPresets = customPresets;
@@ -55,8 +40,7 @@ class ShaderProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
@override
void dispose() {
_savedPresetListenable?.removeListener(_onSettingsChanged);
_customPresetsListenable?.removeListener(_onSettingsChanged);
_settingsBinding.dispose();
super.dispose();
}
@@ -72,12 +56,12 @@ class ShaderProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
}
Future<void> setPreset(ShaderPreset preset) async {
final service = _settingsService ?? await SettingsService.getInstance();
final service = _settingsBinding.settings ?? await SettingsService.getInstance();
await service.write(SettingsService.globalShaderPreset, preset.id);
final changed = _savedPreset.id != preset.id || _currentPreset.id != preset.id;
_savedPreset = preset;
_currentPreset = preset;
if (changed || _savedPresetListenable == null) {
if (changed || _settingsBinding.settings == null) {
safeNotifyListeners();
}
}
@@ -119,7 +103,7 @@ class ShaderProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
}
Future<void> _saveCustomPresets() async {
final service = _settingsService ?? await SettingsService.getInstance();
final service = _settingsBinding.settings ?? await SettingsService.getInstance();
final data = _customPresets.map((p) => p.toJson()).toList();
await service.write(SettingsService.customShaderPresets, data);
}
+13 -28
View File
@@ -1,14 +1,15 @@
import 'dart:async' show unawaited;
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:material_symbols_icons/symbols.dart';
import '../mixins/disposable_change_notifier_mixin.dart';
import '../services/settings_binding_owner.dart';
import '../services/settings_service.dart' as settings;
import '../theme/mono_theme.dart';
class ThemeProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
settings.SettingsService? _settingsService;
ValueNotifier<settings.ThemeMode>? _themeModeListenable;
late final SettingsBindingOwner _settingsBinding;
settings.ThemeMode _themeMode = settings.ThemeMode.system;
late Brightness _systemBrightness;
@@ -19,7 +20,11 @@ class ThemeProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
// async path below lands a microtask too late for the first build.
final loaded = settings.SettingsService.instanceOrNull;
if (loaded != null) _themeMode = loaded.read(settings.SettingsService.themeMode);
_initializeSettings();
_settingsBinding = SettingsBindingOwner(
prefs: const [settings.SettingsService.themeMode],
onRefresh: (service) => _syncThemeMode(service.read(settings.SettingsService.themeMode)),
);
unawaited(_settingsBinding.bind());
WidgetsBinding.instance.platformDispatcher.onPlatformBrightnessChanged = _onBrightnessChanged;
}
@@ -32,33 +37,13 @@ class ThemeProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
@override
void dispose() {
_themeModeListenable?.removeListener(_onThemeModeSettingChanged);
_settingsBinding.dispose();
if (WidgetsBinding.instance.platformDispatcher.onPlatformBrightnessChanged == _onBrightnessChanged) {
WidgetsBinding.instance.platformDispatcher.onPlatformBrightnessChanged = null;
}
super.dispose();
}
Future<void> _initializeSettings() async {
final service = await settings.SettingsService.getInstance();
if (_settingsService == service && _themeModeListenable != null) {
_syncThemeMode(service.read(settings.SettingsService.themeMode));
return;
}
_themeModeListenable?.removeListener(_onThemeModeSettingChanged);
_settingsService = service;
_themeModeListenable = service.listenable(settings.SettingsService.themeMode)
..addListener(_onThemeModeSettingChanged);
_syncThemeMode(_themeModeListenable!.value);
}
void _onThemeModeSettingChanged() {
final listenable = _themeModeListenable;
if (listenable == null) return;
_syncThemeMode(listenable.value);
}
void _syncThemeMode(settings.ThemeMode mode, {bool forceNotify = false}) {
final changed = _themeMode != mode;
_themeMode = mode;
@@ -106,14 +91,14 @@ class ThemeProvider extends ChangeNotifier with DisposableChangeNotifierMixin {
Future<void> setThemeMode(settings.ThemeMode mode) async {
if (_themeMode == mode) return;
final service = _settingsService ?? await settings.SettingsService.getInstance();
final service = _settingsBinding.settings ?? await settings.SettingsService.getInstance();
await service.write(settings.SettingsService.themeMode, mode);
if (_themeModeListenable == null) _syncThemeMode(mode);
if (_settingsBinding.settings == null) _syncThemeMode(mode);
}
Future<void> reload() async {
await _initializeSettings();
final service = _settingsService;
await _settingsBinding.bind();
final service = _settingsBinding.settings;
if (service != null) _syncThemeMode(service.read(settings.SettingsService.themeMode), forceNotify: true);
}