import 'package:shared_preferences/shared_preferences.dart'; enum ConnectionMode { tun, proxy } enum AppRoutingMode { all, exclude, selected } enum ResilienceMode { standard, extreme } abstract final class ConnectionSettings { ConnectionSettings._(); static const String _modeKey = 'connection_mode'; static const String _routingModeKey = 'app_routing_mode'; static const String _appPackagesKey = 'app_routing_packages'; static const String _legacyBlockedAppsKey = 'blocked_apps'; static const String _resilienceModeKey = 'resilience_mode'; static ConnectionMode _mode = ConnectionMode.tun; static AppRoutingMode _routingMode = AppRoutingMode.all; static ResilienceMode _resilienceMode = ResilienceMode.standard; static List _appPackages = const []; static bool _initialized = false; static ConnectionMode get mode => _mode; static AppRoutingMode get routingMode => _routingMode; static ResilienceMode get resilienceMode => _resilienceMode; static List get appPackages => List.unmodifiable(_appPackages); static Future initialize() async { if (_initialized) return; final prefs = await SharedPreferences.getInstance(); final storedMode = prefs.getString(_modeKey); final migrateLegacyAss = storedMode == 'ass'; final migrateLegacyAuto = storedMode == 'auto' || storedMode == null; if (storedMode == ConnectionMode.proxy.name || migrateLegacyAss) { _mode = ConnectionMode.proxy; } else { _mode = ConnectionMode.tun; } final legacyBlocked = prefs.getStringList(_legacyBlockedAppsKey) ?? const []; final storedPackages = prefs.getStringList(_appPackagesKey); _appPackages = _cleanPackages(storedPackages ?? legacyBlocked); final storedRoutingMode = prefs.getString(_routingModeKey); if (migrateLegacyAss) { _routingMode = _appPackages.isEmpty ? AppRoutingMode.all : AppRoutingMode.selected; } else if (storedRoutingMode == AppRoutingMode.exclude.name) { _routingMode = AppRoutingMode.exclude; } else if (storedRoutingMode == AppRoutingMode.selected.name) { _routingMode = AppRoutingMode.selected; } else if (storedRoutingMode == null && legacyBlocked.isNotEmpty) { _routingMode = AppRoutingMode.exclude; } else { _routingMode = AppRoutingMode.all; } _resilienceMode = prefs.getString(_resilienceModeKey) == ResilienceMode.extreme.name ? ResilienceMode.extreme : ResilienceMode.standard; if (migrateLegacyAss) { await prefs.setString(_modeKey, ConnectionMode.proxy.name); await prefs.setString(_routingModeKey, _routingMode.name); } else if (migrateLegacyAuto) { await prefs.setString(_modeKey, ConnectionMode.tun.name); } _initialized = true; } static Future setMode(ConnectionMode mode) async { _mode = mode; _initialized = true; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_modeKey, mode.name); } static Future setRoutingMode(AppRoutingMode mode) async { _routingMode = mode; _initialized = true; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_routingModeKey, mode.name); } static Future setAppPackages(Iterable packages) async { _appPackages = _cleanPackages(packages); _initialized = true; final prefs = await SharedPreferences.getInstance(); await prefs.setStringList(_appPackagesKey, _appPackages); } static Future setResilienceMode(ResilienceMode mode) async { _resilienceMode = mode; _initialized = true; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_resilienceModeKey, mode.name); } static List _cleanPackages(Iterable packages) { final seen = {}; final result = []; for (final raw in packages) { final value = raw.trim(); if (value.isEmpty || !seen.add(value)) continue; result.add(value); } result.sort(); return result; } }