import 'package:signals/signals.dart'; import '../../database/database.dart'; import '../../l10n/locales.dart'; import '../fonts.dart'; /// The reader's presentation choices (spec 8.2) plus the per-app limits they /// move within. Values persist through ReaderSettings in the database. class ReaderSettingsController { ReaderSettingsController(this._db); final MewsDatabase _db; static const minScale = 0.75; static const maxScale = 2.0; static const scaleStep = 0.125; /// The accepted values, in the order the settings page offers them. A /// setting arrives as a link the reader can also type, so a value outside /// these lists is refused rather than stored. static const themeModes = ['light', 'dark', 'system']; static const variants = ['site', 'warm', 'cool', 'green', 'mono']; final font = signal(defaultFontFamily); final fontScale = signal(1.0); final themeMode = signal('system'); final variant = signal('site'); /// The interface language: a shipped locale tag, or [systemLanguage] to take /// whatever the device asks for. final language = signal(systemLanguage); Future load() async { final settings = await _db.readSettings(); if (settings == null) return; font.value = settings.font; fontScale.value = settings.fontScale; themeMode.value = settings.themeMode; variant.value = settings.variant; language.value = settings.language; } Future setFont(String family) async { // Only a family this build bundles: an unknown one would silently render // in the platform's font instead. if (!readerFonts.any((f) => f.family == family) || family == font.value) { return false; } font.value = family; await _persist(); return true; } Future decreaseSize() => _setScale(fontScale.value - scaleStep); Future increaseSize() => _setScale(fontScale.value + scaleStep); Future _setScale(double value) async { if (value < minScale || value > maxScale) return false; fontScale.value = value; await _persist(); return true; } Future setThemeMode(String mode) async { if (!themeModes.contains(mode) || mode == themeMode.value) return false; themeMode.value = mode; await _persist(); return true; } Future setVariant(String variant) async { if (!variants.contains(variant) || variant == this.variant.value) { return false; } this.variant.value = variant; await _persist(); return true; } Future setLanguage(String tag) async { if (tag != systemLanguage && matchLocale(tag) == null) return false; if (tag == language.value) return false; language.value = tag; await _persist(); return true; } Future _persist() => _db.saveSettings( font: font.value, fontScale: fontScale.value, themeMode: themeMode.value, variant: variant.value, language: language.value, ); }