import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/settings/defaults.dart'; import 'package:aves/model/vaults/vaults.dart'; import 'package:aves/widgets/aves_app.dart'; import 'package:aves_model/aves_model.dart'; import 'package:flutter/widgets.dart'; mixin AppSettings on SettingsAccess { static const int recentFilterHistoryMax = 20; void initAppSettings() { vaults.addListener(_onVaultsChanged); } bool get hasAcceptedTerms => getBool(SettingKeys.hasAcceptedTermsKey) ?? SettingsDefaults.hasAcceptedTerms; set hasAcceptedTerms(bool newValue) => set(SettingKeys.hasAcceptedTermsKey, newValue); bool get canUseAnalysisService => getBool(SettingKeys.canUseAnalysisServiceKey) ?? SettingsDefaults.canUseAnalysisService; set canUseAnalysisService(bool newValue) => set(SettingKeys.canUseAnalysisServiceKey, newValue); bool get isInstalledAppAccessAllowed => getBool(SettingKeys.isInstalledAppAccessAllowedKey) ?? SettingsDefaults.isInstalledAppAccessAllowed; set isInstalledAppAccessAllowed(bool newValue) => set(SettingKeys.isInstalledAppAccessAllowedKey, newValue); bool get isErrorReportingAllowed => getBool(SettingKeys.isErrorReportingAllowedKey) ?? SettingsDefaults.isErrorReportingAllowed; set isErrorReportingAllowed(bool newValue) => set(SettingKeys.isErrorReportingAllowedKey, newValue); static const localeSeparator = '-'; Locale? get locale { // exceptionally allow getting locale before settings are initialized final tag = initialized ? getString(SettingKeys.localeKey) : null; if (tag != null) { final codes = tag.split(localeSeparator); return Locale.fromSubtags( languageCode: codes[0], scriptCode: codes[1] == '' ? null : codes[1], countryCode: codes[2] == '' ? null : codes[2], ); } return null; } set locale(Locale? newValue) { String? tag; if (newValue != null) { tag = [ newValue.languageCode, newValue.scriptCode ?? '', newValue.countryCode ?? '', ].join(localeSeparator); } set(SettingKeys.localeKey, tag); resetAppliedLocale(); } List _systemLocalesFallback = []; set systemLocalesFallback(List locales) => _systemLocalesFallback = locales; Locale? _appliedLocale; void resetAppliedLocale() => _appliedLocale = null; Locale get appliedLocale { if (_appliedLocale == null) { final _locale = locale; final preferredLocales = []; if (_locale != null) { preferredLocales.add(_locale); } else { preferredLocales.addAll(WidgetsBinding.instance.platformDispatcher.locales); if (preferredLocales.isEmpty) { // the `window` locales may be empty in a window-less service context preferredLocales.addAll(_systemLocalesFallback); } } _appliedLocale = basicLocaleListResolution(preferredLocales, AvesApp.supportedLocales); } return _appliedLocale!; } bool get forceWesternArabicNumerals => getBool(SettingKeys.forceWesternArabicNumeralsKey) ?? false; set forceWesternArabicNumerals(bool newValue) => set(SettingKeys.forceWesternArabicNumeralsKey, newValue); int get catalogTimeZoneOffsetMillis => getInt(SettingKeys.catalogTimeZoneOffsetMillisKey) ?? 0; set catalogTimeZoneOffsetMillis(int newValue) => set(SettingKeys.catalogTimeZoneOffsetMillisKey, newValue); double getTileExtent(String routeName) => getDouble(SettingKeys.tileExtentPrefixKey + routeName) ?? 0; void setTileExtent(String routeName, double newValue) => set(SettingKeys.tileExtentPrefixKey + routeName, newValue); TileLayout getTileLayout(String routeName) => getEnumOrDefault(SettingKeys.tileLayoutPrefixKey + routeName, SettingsDefaults.tileLayout, TileLayout.values); void setTileLayout(String routeName, TileLayout newValue) => set(SettingKeys.tileLayoutPrefixKey + routeName, newValue.toString()); String get entryRenamingPattern => getString(SettingKeys.entryRenamingPatternKey) ?? SettingsDefaults.entryRenamingPattern; set entryRenamingPattern(String newValue) => set(SettingKeys.entryRenamingPatternKey, newValue); List? get topEntryIds => getStringList(SettingKeys.topEntryIdsKey)?.map(int.tryParse).nonNulls.toList(); set topEntryIds(List? newValue) => set(SettingKeys.topEntryIdsKey, newValue?.map((id) => id.toString()).nonNulls.toList()); List get recentDestinationAlbums => getStringList(SettingKeys.recentDestinationAlbumsKey) ?? []; set recentDestinationAlbums(List newValue) => set(SettingKeys.recentDestinationAlbumsKey, newValue.take(recentFilterHistoryMax).toList()); // recent tags List get _recentTags => (getStringList(SettingKeys.recentTagsKey) ?? []).map(CollectionFilter.fromJson).nonNulls.toList(); set _recentTags(List newValue) => set(SettingKeys.recentTagsKey, newValue.take(recentFilterHistoryMax).map((filter) => filter.toJson()).toList()); // when vaults are unlocked, recent tags are transient and not persisted List? _protectedRecentTags; List get recentTags => vaults.needProtection ? _protectedRecentTags ?? List.of(_recentTags) : _recentTags; set recentTags(List newValue) { if (vaults.needProtection) { _protectedRecentTags = newValue; } else { _recentTags = newValue; } } void _onVaultsChanged() => _protectedRecentTags = null; }