feat(app): add secure routing and runtime resilience

Add explicit TUN and SOCKS5 connection modes, app routing controls, authenticated per-session local SOCKS5, Android network monitoring, persistent haptics, resilient session recovery, notification hardening and client-side Hivemind cleanup.

Keep the hosted flutter_vless_android 1.1.5 runtime as the base and apply the Android compatibility/security patches at build time instead of restoring the unstable vendored runtime.
This commit is contained in:
Naveax committed 2026-08-31 19:31:12 +03:00
1 parent 371db8da9f
commit 8ead3ff249
30 files changed
+3959 -484

No files matched your search

+84
View File
@@ -0,0 +1,84 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
enum HapticKind { tap, selection, success }
abstract final class HapticSettings {
HapticSettings._();
static const String _prefKey = 'haptic_feedback_enabled';
static const MethodChannel _channel =
MethodChannel('com.revoltvpn.app/haptics');
static bool _enabled = true;
static bool _initialized = false;
static bool get enabled => _enabled;
static Future<void> initialize() async {
if (_initialized) return;
try {
final prefs = await SharedPreferences.getInstance();
_enabled = prefs.getBool(_prefKey) ?? true;
} catch (e) {
debugPrint('[Haptics] Failed to load preference: $e');
_enabled = true;
} finally {
_initialized = true;
}
}
static Future<void> setEnabled(bool value) async {
final previous = _enabled;
_enabled = value;
_initialized = true;
try {
final prefs = await SharedPreferences.getInstance();
final saved = await prefs.setBool(_prefKey, value);
if (!saved) throw StateError('Could not save haptic setting');
} catch (e) {
_enabled = previous;
debugPrint('[Haptics] Failed to save preference: $e');
rethrow;
}
}
static void tap() => unawaited(_impact(HapticKind.tap));
static void selection() => unawaited(_impact(HapticKind.selection));
static void success() => unawaited(_impact(HapticKind.success));
static Future<void> _impact(HapticKind kind) async {
if (!_initialized) await initialize();
if (!_enabled || kIsWeb) return;
if (defaultTargetPlatform == TargetPlatform.android) {
try {
final handled = await _channel.invokeMethod<bool>(
'impact',
<String, Object>{'kind': kind.name},
) ??
false;
if (handled) return;
} catch (e) {
debugPrint('[Haptics] Native vibration unavailable: $e');
}
}
switch (kind) {
case HapticKind.tap:
await HapticFeedback.lightImpact();
break;
case HapticKind.selection:
await HapticFeedback.selectionClick();
break;
case HapticKind.success:
await HapticFeedback.mediumImpact();
break;
}
}
}