138 lines
4.7 KiB
Dart
138 lines
4.7 KiB
Dart
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 {
|
|
late final SettingsBindingOwner _settingsBinding;
|
|
|
|
ShaderPreset _savedPreset = ShaderPreset.none;
|
|
ShaderPreset _currentPreset = ShaderPreset.none;
|
|
List<ShaderPreset> _customPresets = [];
|
|
List<ShaderPreset> _allPresets = ShaderPreset.allPresets;
|
|
bool _initialized = false;
|
|
|
|
ShaderProvider() {
|
|
_settingsBinding = SettingsBindingOwner(
|
|
prefs: [SettingsService.globalShaderPreset, SettingsService.customShaderPresets],
|
|
onRefresh: _syncFromSettings,
|
|
);
|
|
unawaited(_settingsBinding.bind());
|
|
}
|
|
|
|
void _syncFromSettings(SettingsService service) {
|
|
final customPresets = <ShaderPreset>[];
|
|
for (final json in service.read(SettingsService.customShaderPresets)) {
|
|
try {
|
|
final preset = ShaderPreset.fromJson(json);
|
|
final fileName = preset.fileName;
|
|
if (preset.type == ShaderPresetType.custom &&
|
|
fileName != null &&
|
|
ShaderAssetLoader.isValidCustomShaderFileName(fileName)) {
|
|
customPresets.add(preset);
|
|
}
|
|
} on Object {
|
|
// Imported settings can contain structurally invalid custom rows.
|
|
}
|
|
}
|
|
_customPresets = customPresets;
|
|
_refreshAllPresets();
|
|
|
|
final presetId = service.read(SettingsService.globalShaderPreset);
|
|
_savedPreset = findPresetById(presetId) ?? ShaderPreset.none;
|
|
_currentPreset = _savedPreset;
|
|
|
|
_initialized = true;
|
|
safeNotifyListeners();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_settingsBinding.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
bool get initialized => _initialized;
|
|
ShaderPreset get savedPreset => _savedPreset;
|
|
ShaderPreset get currentPreset => _currentPreset;
|
|
List<ShaderPreset> get allPresets => _allPresets;
|
|
List<ShaderPreset> get customPresets => _customPresets;
|
|
bool get isShaderEnabled => _currentPreset.type != ShaderPresetType.none;
|
|
|
|
ShaderPreset? findPresetById(String id) {
|
|
return ShaderPreset.fromId(id) ?? _customPresets.firstWhereOrNull((p) => p.id == id);
|
|
}
|
|
|
|
Future<void> setPreset(ShaderPreset preset) async {
|
|
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 || _settingsBinding.settings == null) {
|
|
safeNotifyListeners();
|
|
}
|
|
}
|
|
|
|
/// Update the current preset without persisting (e.g. toggling off temporarily)
|
|
void setCurrentPreset(ShaderPreset preset) {
|
|
if (_currentPreset.id != preset.id) {
|
|
_currentPreset = preset;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// Import a custom shader from a file path.
|
|
/// Copies the file to the custom shaders directory and creates a preset.
|
|
Future<ShaderPreset> importCustomShader(String filePath, String displayName) async {
|
|
final storedFileName = await ShaderAssetLoader.importCustomShader(filePath);
|
|
final id = 'custom_$storedFileName';
|
|
|
|
final preset = ShaderPreset(id: id, name: displayName, type: ShaderPresetType.custom, fileName: storedFileName);
|
|
|
|
_customPresets.add(preset);
|
|
_refreshAllPresets();
|
|
await _saveCustomPresets();
|
|
return preset;
|
|
}
|
|
|
|
/// Delete a custom shader preset and its file.
|
|
Future<void> deleteCustomShader(ShaderPreset preset) async {
|
|
final wasActive = _currentPreset.id == preset.id || _savedPreset.id == preset.id;
|
|
if (preset.fileName != null) {
|
|
await ShaderAssetLoader.deleteCustomShader(preset.fileName!);
|
|
}
|
|
_customPresets.removeWhere((p) => p.id == preset.id);
|
|
_refreshAllPresets();
|
|
await _saveCustomPresets();
|
|
|
|
// Reset to none if the deleted preset was active
|
|
if (wasActive) {
|
|
await setPreset(ShaderPreset.none);
|
|
}
|
|
}
|
|
|
|
void _refreshAllPresets() {
|
|
_allPresets = _customPresets.isEmpty
|
|
? ShaderPreset.allPresets
|
|
: List.unmodifiable([...ShaderPreset.allPresets, ..._customPresets]);
|
|
}
|
|
|
|
Future<void> _saveCustomPresets() async {
|
|
final service = _settingsBinding.settings ?? await SettingsService.getInstance();
|
|
final data = _customPresets.map((p) => p.toJson()).toList();
|
|
await service.write(SettingsService.customShaderPresets, data);
|
|
}
|
|
|
|
/// Reset to default (no shaders)
|
|
Future<void> reset() async {
|
|
await setPreset(ShaderPreset.none);
|
|
}
|
|
}
|