import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:async/async.dart'; import 'package:http/http.dart' as http; import 'package:matrix/matrix_api_lite/utils/logs.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:fluffychat/utils/platform_infos.dart'; enum AppSettings { textMessageMaxLength('textMessageMaxLength', 16384), audioRecordingNumChannels('audioRecordingNumChannels', 1), audioRecordingAutoGain('audioRecordingAutoGain', true), audioRecordingEchoCancel('audioRecordingEchoCancel', false), audioRecordingNoiseSuppress('audioRecordingNoiseSuppress', true), audioRecordingBitRate('audioRecordingBitRate', 64000), audioRecordingSamplingRate('audioRecordingSamplingRate', 44100), showNoGoogle('chat.fluffy.show_no_google', false), unifiedPushRegistered('chat.fluffy.unifiedpush.registered', false), unifiedPushEndpoint('chat.fluffy.unifiedpush.endpoint', ''), pushNotificationsGatewayUrl( 'pushNotificationsGatewayUrl', 'https://push.fluffychat.im/_matrix/push/v1/notify', ), pushNotificationsPusherFormat( 'pushNotificationsPusherFormat', 'event_id_only', ), renderHtml('chat.fluffy.renderHtml', true), fontSizeFactor('chat.fluffy.font_size_factor', 1.0), hideRedactedEvents('chat.fluffy.hideRedactedEvents', false), hideUnknownEvents('chat.fluffy.hideUnknownEvents', true), separateChatTypes('chat.fluffy.separateChatTypes', false), autoplayImages('chat.fluffy.autoplay_images', true), sendTypingNotifications('chat.fluffy.send_typing_notifications', true), sendPublicReadReceipts('chat.fluffy.send_public_read_receipts', true), swipeRightToLeftToReply('chat.fluffy.swipeRightToLeftToReply', true), sendOnEnter('chat.fluffy.send_on_enter', false), showPresences('chat.fluffy.show_presences', true), displayNavigationRail('chat.fluffy.display_navigation_rail', false), experimentalVoip('chat.fluffy.experimental_voip', false), shareKeysWith('chat.fluffy.share_keys_with_2', 'all'), noEncryptionWarningShown( 'chat.fluffy.no_encryption_warning_shown', false, ), displayChatDetailsColumn( 'chat.fluffy.display_chat_details_column', false, ), // AppConfig-mirrored settings applicationName('chat.fluffy.application_name', 'FluffyChat'), defaultHomeserver('chat.fluffy.default_homeserver', 'matrix.org'), // colorSchemeSeed stored as ARGB int colorSchemeSeedInt( 'chat.fluffy.color_scheme_seed', 0xFF5625BA, ), enableSoftLogout('chat.fluffy.enable_soft_logout', false); final String key; final T defaultValue; const AppSettings(this.key, this.defaultValue); static SharedPreferences get store => _store!; static SharedPreferences? _store; static Future init({loadWebConfigFile = true}) async { if (AppSettings._store != null) return AppSettings.store; final store = AppSettings._store = await SharedPreferences.getInstance(); // Migrate wrong datatype for fontSizeFactor final fontSizeFactorString = Result(() => store.getString(AppSettings.fontSizeFactor.key)) .asValue ?.value; if (fontSizeFactorString != null) { Logs().i('Migrate wrong datatype for fontSizeFactor!'); await store.remove(AppSettings.fontSizeFactor.key); final fontSizeFactor = double.tryParse(fontSizeFactorString); if (fontSizeFactor != null) { await store.setDouble(AppSettings.fontSizeFactor.key, fontSizeFactor); } } if (store.getBool(AppSettings.sendOnEnter.key) == null) { await store.setBool(AppSettings.sendOnEnter.key, !PlatformInfos.isMobile); } if (kIsWeb && loadWebConfigFile) { try { final configJsonString = utf8.decode((await http.get(Uri.parse('config.json'))).bodyBytes); final configJson = json.decode(configJsonString) as Map; for (final setting in AppSettings.values) { if (store.get(setting.key) != null) continue; final configValue = configJson[setting.name]; if (configValue == null) continue; if (configValue is bool) { await store.setBool(setting.key, configValue); } if (configValue is String) { await store.setString(setting.key, configValue); } if (configValue is int) { await store.setInt(setting.key, configValue); } if (configValue is double) { await store.setDouble(setting.key, configValue); } } } on FormatException catch (_) { Logs().v('[ConfigLoader] config.json not found'); } catch (e) { Logs().v('[ConfigLoader] config.json not found', e); } } return store; } } extension AppSettingsBoolExtension on AppSettings { bool get value { final value = Result(() => AppSettings.store.getBool(key)); final error = value.asError; if (error != null) { Logs().e( 'Unable to fetch $key from storage. Removing entry...', error.error, error.stackTrace, ); } return value.asValue?.value ?? defaultValue; } Future setItem(bool value) => AppSettings.store.setBool(key, value); } extension AppSettingsStringExtension on AppSettings { String get value { final value = Result(() => AppSettings.store.getString(key)); final error = value.asError; if (error != null) { Logs().e( 'Unable to fetch $key from storage. Removing entry...', error.error, error.stackTrace, ); } return value.asValue?.value ?? defaultValue; } Future setItem(String value) => AppSettings.store.setString(key, value); } extension AppSettingsIntExtension on AppSettings { int get value { final value = Result(() => AppSettings.store.getInt(key)); final error = value.asError; if (error != null) { Logs().e( 'Unable to fetch $key from storage. Removing entry...', error.error, error.stackTrace, ); } return value.asValue?.value ?? defaultValue; } Future setItem(int value) => AppSettings.store.setInt(key, value); } extension AppSettingsDoubleExtension on AppSettings { double get value { final value = Result(() => AppSettings.store.getDouble(key)); final error = value.asError; if (error != null) { Logs().e( 'Unable to fetch $key from storage. Removing entry...', error.error, error.stackTrace, ); } return value.asValue?.value ?? defaultValue; } Future setItem(double value) => AppSettings.store.setDouble(key, value); }