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

+65
View File
@@ -0,0 +1,65 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:revoltvpn/logic/haptic_settings.dart';
/// Gives short touch taps the same haptic feedback across the app.
/// Scroll gestures are ignored by checking travel distance and touch duration.
class AppHapticSurface extends StatefulWidget {
final Widget child;
const AppHapticSurface({super.key, required this.child});
@override
State<AppHapticSurface> createState() => _AppHapticSurfaceState();
}
class _PointerStart {
final Offset position;
final DateTime time;
const _PointerStart(this.position, this.time);
}
class _AppHapticSurfaceState extends State<AppHapticSurface> {
static const double _maxTapTravel = 18;
static const Duration _maxTapDuration = Duration(milliseconds: 700);
final Map<int, _PointerStart> _starts = <int, _PointerStart>{};
bool _supportsHaptics(PointerDeviceKind kind) {
return kind == PointerDeviceKind.touch ||
kind == PointerDeviceKind.stylus ||
kind == PointerDeviceKind.invertedStylus;
}
void _onDown(PointerDownEvent event) {
if (!_supportsHaptics(event.kind)) return;
_starts[event.pointer] = _PointerStart(event.position, DateTime.now());
}
void _onCancel(PointerCancelEvent event) {
_starts.remove(event.pointer);
}
void _onUp(PointerUpEvent event) {
final start = _starts.remove(event.pointer);
if (start == null || !_supportsHaptics(event.kind)) return;
final travelled = (event.position - start.position).distance;
final elapsed = DateTime.now().difference(start.time);
if (travelled <= _maxTapTravel && elapsed <= _maxTapDuration) {
HapticSettings.tap();
}
}
@override
Widget build(BuildContext context) {
return Listener(
behavior: HitTestBehavior.translucent,
onPointerDown: _onDown,
onPointerUp: _onUp,
onPointerCancel: _onCancel,
child: widget.child,
);
}
}