import "package:flutter/material.dart"; import "package:shared_preferences/shared_preferences.dart"; import "models.dart"; /// App-wide appearance preferences (theme / locale / date format / currency / /// font size), mirroring the web app's prefs.js. Persisted to SharedPreferences /// so the chosen theme survives a restart before /api/me loads, and exposed as a /// ChangeNotifier so MaterialApp and date formatting react to changes. class AppSettings extends ChangeNotifier { static const _kTheme = "cc_theme"; static const _kLocale = "cc_locale"; static const _kDateFormat = "cc_dateFormat"; static const _kCurrency = "cc_currency"; static const _kFontSize = "cc_fontSize"; String theme = "system"; // light | dark | system String locale = "en-US"; // BCP-47 language-REGION String dateFormat = "YMD"; // YMD | DMY_NUM | DMY | MDY String currency = "USD"; // ISO 4217 code String fontSize = "medium"; // small | medium | large /// Language and region are two controls over the one stored tag, so the pair /// can be mixed freely (English in Poland, say). String get language => locale.split("-").first; String get region => locale.split("-").length > 1 ? locale.split("-")[1] : "US"; Future loadFromStorage() async { final prefs = await SharedPreferences.getInstance(); theme = prefs.getString(_kTheme) ?? theme; locale = prefs.getString(_kLocale) ?? locale; dateFormat = prefs.getString(_kDateFormat) ?? dateFormat; currency = prefs.getString(_kCurrency) ?? currency; fontSize = prefs.getString(_kFontSize) ?? fontSize; notifyListeners(); } Future _persist() async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_kTheme, theme); await prefs.setString(_kLocale, locale); await prefs.setString(_kDateFormat, dateFormat); await prefs.setString(_kCurrency, currency); await prefs.setString(_kFontSize, fontSize); } /// Sync from a freshly fetched profile (login, boot, settings saves). void applyFromProfile(UserProfile p) { theme = p.theme; locale = p.locale; dateFormat = p.dateFormat; currency = p.currency; fontSize = p.fontSize; _persist(); notifyListeners(); } /// Optimistically apply a single changed field (used by Settings so the UI /// reacts instantly while the PATCH is in flight). void patch({ String? theme, String? locale, String? dateFormat, String? currency, String? fontSize, }) { if (theme != null) this.theme = theme; if (locale != null) this.locale = locale; if (dateFormat != null) this.dateFormat = dateFormat; if (currency != null) this.currency = currency; if (fontSize != null) this.fontSize = fontSize; _persist(); notifyListeners(); } ThemeMode get themeMode => switch (theme) { "light" => ThemeMode.light, "dark" => ThemeMode.dark, _ => ThemeMode.system, }; double get textScale => switch (fontSize) { "small" => 0.9375, "large" => 1.125, _ => 1.0, }; }