95 lines
2.9 KiB
Dart
95 lines
2.9 KiB
Dart
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', 'host', '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<void> 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<bool> 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<bool> decreaseSize() => _setScale(fontScale.value - scaleStep);
|
|
Future<bool> increaseSize() => _setScale(fontScale.value + scaleStep);
|
|
|
|
Future<bool> _setScale(double value) async {
|
|
if (value < minScale || value > maxScale) return false;
|
|
fontScale.value = value;
|
|
await _persist();
|
|
return true;
|
|
}
|
|
|
|
Future<bool> setThemeMode(String mode) async {
|
|
if (!themeModes.contains(mode) || mode == themeMode.value) return false;
|
|
themeMode.value = mode;
|
|
await _persist();
|
|
return true;
|
|
}
|
|
|
|
Future<bool> setVariant(String variant) async {
|
|
if (!variants.contains(variant) || variant == this.variant.value) {
|
|
return false;
|
|
}
|
|
this.variant.value = variant;
|
|
await _persist();
|
|
return true;
|
|
}
|
|
|
|
Future<bool> 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<void> _persist() => _db.saveSettings(
|
|
font: font.value,
|
|
fontScale: fontScale.value,
|
|
themeMode: themeMode.value,
|
|
variant: variant.value,
|
|
language: language.value,
|
|
);
|
|
}
|