Files
SpotiFLAC-Mobile/lib/providers/theme_provider.dart
T

131 lines
4.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotiflac_android/models/theme_settings.dart';
final initialThemeSettingsProvider = Provider<ThemeSettings>(
(ref) => const ThemeSettings(),
);
ThemeSettings loadBootstrapThemeSettings(SharedPreferences prefs) {
return ThemeSettings(
themeMode: themeModeFromString(prefs.getString(kThemeModeKey)),
useDynamicColor: prefs.getBool(kUseDynamicColorKey) ?? true,
seedColorValue: prefs.getInt(kSeedColorKey) ?? kDefaultSeedColor,
useAmoled: prefs.getBool(kUseAmoledKey) ?? false,
style: themeStyleFromString(prefs.getString(kThemeStyleKey)),
mornyeAccent: mornyeAccentFromString(prefs.getString(kMornyeAccentKey)),
useSystemFont: prefs.getBool(kUseSystemFontKey) ?? false,
mornyeGlassClarity: normalizeMornyeGlassClarity(
prefs.getDouble(kMornyeGlassClarityKey),
),
);
}
final themeProvider = NotifierProvider<ThemeNotifier, ThemeSettings>(() {
return ThemeNotifier();
});
class ThemeNotifier extends Notifier<ThemeSettings> {
ThemeNotifier({Future<SharedPreferences>? preferences})
: _prefs = preferences ?? SharedPreferences.getInstance();
final Future<SharedPreferences> _prefs;
late Future<void> _loadFuture;
Future<void> _saveChain = Future<void>.value();
final _loadingEdits = <ThemeSettings Function(ThemeSettings)>[];
bool _loaded = false;
@override
ThemeSettings build() {
_loadFuture = _loadFromStorage();
return ref.read(initialThemeSettingsProvider);
}
Future<void> _loadFromStorage() async {
try {
final prefs = await _prefs;
var loaded = loadBootstrapThemeSettings(prefs);
for (final edit in _loadingEdits) {
loaded = edit(loaded);
}
if (ref.mounted) state = loaded;
} catch (e) {
debugPrint('Error loading theme settings: $e');
} finally {
_loaded = true;
_loadingEdits.clear();
}
}
void _editState(ThemeSettings Function(ThemeSettings) edit) {
if (!_loaded) _loadingEdits.add(edit);
state = edit(state);
}
Future<void> _saveToStorage() => _saveChain = _saveChain.then((_) async {
try {
await _loadFuture;
final prefs = await _prefs;
if (!ref.mounted) return;
final snapshot = state;
await prefs.setString(kThemeModeKey, snapshot.themeMode.name);
await prefs.setBool(kUseDynamicColorKey, snapshot.useDynamicColor);
await prefs.setInt(kSeedColorKey, snapshot.seedColorValue);
await prefs.setBool(kUseAmoledKey, snapshot.useAmoled);
await prefs.setString(kThemeStyleKey, snapshot.style.name);
await prefs.setString(kMornyeAccentKey, snapshot.mornyeAccent.name);
await prefs.setBool(kUseSystemFontKey, snapshot.useSystemFont);
await prefs.setDouble(
kMornyeGlassClarityKey,
snapshot.mornyeGlassClarity,
);
} catch (e) {
debugPrint('Error saving theme settings: $e');
}
});
Future<void> setThemeMode(ThemeMode mode) async {
_editState((current) => current.copyWith(themeMode: mode));
await _saveToStorage();
}
Future<void> setStyle(AppThemeStyle style) async {
_editState((current) => current.copyWith(style: style));
await _saveToStorage();
}
Future<void> setUseDynamicColor(bool value) async {
_editState((current) => current.copyWith(useDynamicColor: value));
await _saveToStorage();
}
Future<void> setSeedColor(Color color) async {
_editState((current) => current.copyWith(seedColorValue: color.toARGB32()));
await _saveToStorage();
}
Future<void> setUseAmoled(bool value) async {
_editState((current) => current.copyWith(useAmoled: value));
await _saveToStorage();
}
Future<void> setMornyeAccent(MornyeAccent accent) async {
_editState((current) => current.copyWith(mornyeAccent: accent));
await _saveToStorage();
}
Future<void> setUseSystemFont(bool value) async {
_editState((current) => current.copyWith(useSystemFont: value));
await _saveToStorage();
}
Future<void> setMornyeGlassClarity(
double value, {
bool persist = true,
}) async {
_editState((current) => current.copyWith(mornyeGlassClarity: value));
if (persist) await _saveToStorage();
}
}