refactor(app): debloat 3.3.1 and fix startup restoration

Maintainer changes on top of PR #2 (Naveax). Reduces the release to two
deliberate connection modes and resolves the issues found in review:

- Lock-screen privacy: move VISIBILITY_PRIVATE and a generic publicVersion
  into MainActivity.updateVpnNotification. The PR's fix lived in an
  unreferenced class and never reached the live notification.
- Haptics: restore the default to off, and reduce HapticSettings to a
  single success() on connect/disconnect via the native channel.
- SOCKS5: make it a real proxyOnly local-proxy mode rather than a TUN
  connection under a different label. TUN stays the default.
- Health probe: restore the idle-only guard so /health is no longer polled
  every 30s while connected.
- Recovery: add a _connectionEpoch counter so connect() aborts an
  in-flight Extreme recovery.
- Startup restoration: rebuild the recovery snapshot from the still-active
  session after an app-process restart (TUN), and surface an honest
  orphaned state with a Reconnect action in proxy mode.

Drops per-app routing entirely. It only ever functioned in TUN --
addDisallowedApplication lives inside the VPN-interface setup that
proxyOnly skips -- and its allowlist half had no Dart caller.

Also removes flutter_local_notifications, the global tap-haptic surface,
and unused runtime telemetry.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
esefxdzandClaude Opus 5 committed 2026-08-31 23:31:51 +03:00
1 parent a71161e7e5
commit 6fcde9dd7b
18 files changed
+271 -1027

No files matched your search

+7 -66
View File
@@ -1,73 +1,40 @@
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<String> _appPackages = const <String>[];
static bool _initialized = false;
static ConnectionMode get mode => _mode;
static AppRoutingMode get routingMode => _routingMode;
static ResilienceMode get resilienceMode => _resilienceMode;
static List<String> get appPackages => List.unmodifiable(_appPackages);
static Future<void> 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 <String>[];
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;
}
// Legacy 'ass' was the pre-V3 SOCKS5 label; map it to proxy. Everything
// else (including the old 'auto') is TUN — there is no runtime auto mode.
_mode = storedMode == ConnectionMode.proxy.name || storedMode == 'ass'
? ConnectionMode.proxy
: ConnectionMode.tun;
_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);
if (storedMode != _mode.name) {
await prefs.setString(_modeKey, _mode.name);
}
_initialized = true;
@@ -80,36 +47,10 @@ abstract final class ConnectionSettings {
await prefs.setString(_modeKey, mode.name);
}
static Future<void> setRoutingMode(AppRoutingMode mode) async {
_routingMode = mode;
_initialized = true;
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_routingModeKey, mode.name);
}
static Future<void> setAppPackages(Iterable<String> packages) async {
_appPackages = _cleanPackages(packages);
_initialized = true;
final prefs = await SharedPreferences.getInstance();
await prefs.setStringList(_appPackagesKey, _appPackages);
}
static Future<void> setResilienceMode(ResilienceMode mode) async {
_resilienceMode = mode;
_initialized = true;
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_resilienceModeKey, mode.name);
}
static List<String> _cleanPackages(Iterable<String> packages) {
final seen = <String>{};
final result = <String>[];
for (final raw in packages) {
final value = raw.trim();
if (value.isEmpty || !seen.add(value)) continue;
result.add(value);
}
result.sort();
return result;
}
}