import 'package:flutter/foundation.dart'; import 'package:umbrix/core/app_info/app_info_provider.dart'; import 'package:umbrix/core/model/environment.dart'; import 'package:umbrix/core/preferences/actions_at_closing.dart'; // import 'package:umbrix/core/model/region.dart'; import 'package:umbrix/core/preferences/preferences_provider.dart'; import 'package:umbrix/core/utils/preferences_utils.dart'; import 'package:umbrix/features/connection/model/connection_status.dart'; import 'package:umbrix/features/connection/notifier/connection_notifier.dart'; import 'package:umbrix/features/per_app_proxy/model/per_app_proxy_mode.dart'; import 'package:umbrix/features/profile/notifier/active_profile_notifier.dart'; import 'package:umbrix/utils/platform_utils.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'general_preferences.g.dart'; bool _debugIntroPage = false; abstract class Preferences { static final introCompleted = PreferencesNotifier.create( "intro_completed", false, overrideValue: _debugIntroPage && kDebugMode ? false : null, ); static final silentStart = PreferencesNotifier.create( "silent_start", false, ); static final disableMemoryLimit = PreferencesNotifier.create( "disable_memory_limit", // disable memory limit on desktop by default PlatformUtils.isDesktop, ); static final perAppProxyMode = PreferencesNotifier.create( "per_app_proxy_mode", PerAppProxyMode.exclude, mapFrom: PerAppProxyMode.values.byName, mapTo: (value) => value.name, ); static final markNewProfileActive = PreferencesNotifier.create( "mark_new_profile_active", true, ); static final dynamicNotification = PreferencesNotifier.create( "dynamic_notification", true, ); static final autoCheckIp = PreferencesNotifier.create( "auto_check_ip", true, ); static final startedByUser = PreferencesNotifier.create( "started_by_user", false, ); static final storeReviewedByUser = PreferencesNotifier.create( "store_reviewed_by_user", false, ); static final actionAtClose = PreferencesNotifier.create( "action_at_close", ActionsAtClosing.ask, mapFrom: ActionsAtClosing.values.byName, mapTo: (value) => value.name, ); } @Riverpod(keepAlive: true) class DebugModeNotifier extends _$DebugModeNotifier { late final _pref = PreferencesEntry( preferences: ref.watch(sharedPreferencesProvider).requireValue, key: "debug_mode", defaultValue: ref.read(environmentProvider) == Environment.dev, ); @override bool build() => _pref.read(); Future update(bool value) { state = value; return _pref.write(value); } } @Riverpod(keepAlive: true) class PerAppProxyList extends _$PerAppProxyList { late final _include = PreferencesEntry( preferences: ref.watch(sharedPreferencesProvider).requireValue, key: "per_app_proxy_include_list", defaultValue: [], ); late final _exclude = PreferencesEntry( preferences: ref.watch(sharedPreferencesProvider).requireValue, key: "per_app_proxy_exclude_list", defaultValue: [], ); @override List build() { // Слушаем изменения режима и перестраиваем список final mode = ref.watch(Preferences.perAppProxyMode); return mode == PerAppProxyMode.include ? _include.read() : _exclude.read(); } Future update(List value) async { print('[PerAppProxyList] update() вызван с ${value.length} приложениями'); final mode = ref.read(Preferences.perAppProxyMode); print('[PerAppProxyList] Текущий режим: $mode'); // Сначала сохраняем в SharedPreferences if (mode == PerAppProxyMode.include) { await _include.write(value); print('[PerAppProxyList] Записан include список: $value'); } else { await _exclude.write(value); print('[PerAppProxyList] Записан exclude список: $value'); } // Затем обновляем локальное состояние state = value; print('[PerAppProxyList] State обновлён'); // Автоматически перезапускаем VPN если он активен print('[PerAppProxyList] Вызываю _reconnectVpnIfActive()'); await _reconnectVpnIfActive(); } Future _reconnectVpnIfActive() async { try { final connectionNotifier = await ref.read(connectionNotifierProvider.future); if (connectionNotifier is Connected) { final profile = await ref.read(activeProfileProvider.future); await ref.read(connectionNotifierProvider.notifier).reconnect(profile); } } catch (_) { // Игнорируем ошибки если connection provider не инициализирован } } } @Riverpod(keepAlive: true) class ExcludedDomainsList extends _$ExcludedDomainsList { late final _pref = PreferencesEntry( preferences: ref.watch(sharedPreferencesProvider).requireValue, key: "excluded_domains_list", defaultValue: [], ); @override List build() => _pref.read(); Future update(List value) async { state = value; await _pref.write(value); // Автоматически перезапускаем VPN если он активен await _reconnectVpnIfActive(); } Future _reconnectVpnIfActive() async { try { final connectionNotifier = await ref.read(connectionNotifierProvider.future); if (connectionNotifier is Connected) { final profile = await ref.read(activeProfileProvider.future); await ref.read(connectionNotifierProvider.notifier).reconnect(profile); } } catch (_) { // Игнорируем ошибки если connection provider не инициализирован } } }