v2.0.0: VLESS cleanup — remove bonus ads, throttling, fix Xray compliance, rebrand colors
This commit is contained in:
1 parent
10a1450292
commit
d106356ca6
20 files changed
+318
-308
No files matched your search
@@ -0,0 +1,74 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// =============================================================================
|
||||
// app_colors.dart — Single source of truth for every color in ReVoltVPN
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Import this file and reference AppColors.* instead of hardcoding hex values
|
||||
// or Color.fromRGBO() calls anywhere else in the app.
|
||||
// =============================================================================
|
||||
|
||||
abstract final class AppColors {
|
||||
AppColors._();
|
||||
|
||||
// ── Primary: Cyan ──────────────────────────────────────────────────────────
|
||||
static const Color cyan = Color(0xFF00E5FF);
|
||||
static const Color cyan15 = Color(0x2600E5FF); // 15 % opacity
|
||||
static const Color cyan25 = Color(0x4000E5FF); // 25 % opacity
|
||||
static const Color cyan50 = Color(0x8000E5FF); // 50 % opacity
|
||||
static const Color cyan60 = Color(0x9900E5FF); // 60 % opacity
|
||||
static const Color cyan70 = Color(0xB300E5FF); // 70 % opacity
|
||||
static const Color cyan05 = Color(0x0D00E5FF); // 5 % opacity
|
||||
static const Color cyanGlow = Color(0x8800E5FF); // glowing border
|
||||
|
||||
// ── Backgrounds ────────────────────────────────────────────────────────────
|
||||
static const Color bgDeep = Color(0xFF0D1117); // intro / scaffold
|
||||
static const Color bgDark = Color(0xFF1A202C); // button circle
|
||||
static const Color bgSurface = Color(0xFF151C28); // colorScheme surface
|
||||
static const Color bgCard = Color(0xFF1E2533); // bottom bar, snackbar
|
||||
static const Color bgOverlay = Color(0xAA0D1117); // semi-transparent overlay
|
||||
|
||||
// ── Slate / Gray ───────────────────────────────────────────────────────────
|
||||
static const Color slate = Color(0xFF4A5568);
|
||||
static const Color slate15 = Color(0x264A5568); // 15 % opacity
|
||||
static const Color slate50 = Color(0x804A5568); // 50 % opacity
|
||||
static const Color slate70 = Color(0xB34A5568); // 70 % opacity
|
||||
static const Color slateAA = Color(0xAA4A5568); // ~67 % (legacy usage)
|
||||
|
||||
// ── Text ───────────────────────────────────────────────────────────────────
|
||||
static const Color textWhite = Colors.white;
|
||||
static const Color textDim = Colors.white54;
|
||||
static const Color textWhite80 = Color(0xCCFFFFFF); // 80 % white
|
||||
static const Color textMuted = Color(0xFFA0AEC0); // dialog body text
|
||||
|
||||
// ── Semantic ───────────────────────────────────────────────────────────────
|
||||
static const Color green = Color(0xFF00E676);
|
||||
static const Color green50 = Color(0x8000E676); // 50 % opacity
|
||||
static const Color red = Color(0xFFEF5350);
|
||||
|
||||
// ── Glass / Borders ────────────────────────────────────────────────────────
|
||||
static const Color glassBg = Color(0x22FFFFFF); // subtle glass background
|
||||
static const Color glassBorder = Color(0x33FFFFFF); // muted translucent border
|
||||
|
||||
// ── Intro screen snackbars ─────────────────────────────────────────────────
|
||||
static const Color snackSuccess = Color(0xFF006064);
|
||||
static const Color snackError = Color(0xFF5D4037);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// FUTURE — Yellow palette (not yet wired into the UI)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
static const Color yellow = Color(0xFFFFD600);
|
||||
static const Color yellowDark = Color(0xFFFFAB00);
|
||||
static const Color yellowLight = Color(0xFFFFFF00);
|
||||
static const Color yellowFaded = Color(0x1AFFD600);
|
||||
static const Color yellowAmber = Color(0xFFFFC107);
|
||||
static const Color yellowMustard = Color(0xFFC6A700);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// FUTURE — Black palette (not yet wired into the UI)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
static const Color black = Color(0xFF000000);
|
||||
static const Color blackOff = Color(0xFF0A0A0A);
|
||||
static const Color blackFaded = Color(0xAA000000);
|
||||
static const Color blackWarm = Color(0xFF121212);
|
||||
static const Color blackCharcoal = Color(0xFF1A1A1A);
|
||||
}
|
||||
@@ -17,7 +17,6 @@ abstract final class AppConfig {
|
||||
|
||||
// ── VLESS ──────────────────────────────────────────────────────────────
|
||||
static const int serverPort = 443;
|
||||
static const String vlessFlow = 'xtls-rprx-vision';
|
||||
static const String vlessSecurity = 'tls';
|
||||
static const String vlessType = 'ws';
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ class HivemindService {
|
||||
try {
|
||||
final customData = jsonEncode({
|
||||
'device_id': deviceId,
|
||||
'ad_type': 'main_ad',
|
||||
'nonce': nonce,
|
||||
});
|
||||
final fakeAdmobPingUrl = Uri.parse(
|
||||
@@ -75,7 +74,6 @@ class HivemindService {
|
||||
'?path=${Uri.encodeComponent(AppConfig.vlessPath)}'
|
||||
'&security=${AppConfig.vlessSecurity}'
|
||||
'&type=${AppConfig.vlessType}'
|
||||
'&flow=${AppConfig.vlessFlow}'
|
||||
'#ReVoltVPN';
|
||||
|
||||
_expectedNonce = null; // consumed successfully
|
||||
|
||||
@@ -22,7 +22,6 @@ class SessionTimer extends ChangeNotifier {
|
||||
int _remainingSeconds = 0;
|
||||
int _quotaBytes = 0;
|
||||
int _usedBytes = 0;
|
||||
bool _isThrottled = false;
|
||||
|
||||
// ── Sync / Network Health ──────────────────────────────────────────────────
|
||||
bool _hasSyncedOnce = false;
|
||||
@@ -65,7 +64,6 @@ class SessionTimer extends ChangeNotifier {
|
||||
int get quotaBytes => _quotaBytes;
|
||||
int get usedBytes => _usedBytes;
|
||||
int get remainingBytes => _quotaBytes > _usedBytes ? _quotaBytes - _usedBytes : 0;
|
||||
bool get isThrottled => _isThrottled;
|
||||
double get currentSpeedKBps => _currentSpeedKBps;
|
||||
|
||||
String get formatted {
|
||||
@@ -136,7 +134,6 @@ class SessionTimer extends ChangeNotifier {
|
||||
_usedBytes = 0;
|
||||
_lastUsedBytes = 0;
|
||||
_currentSpeedKBps = 0.0;
|
||||
_isThrottled = false;
|
||||
_tickCount = 0;
|
||||
_hasSyncedOnce = false;
|
||||
_consecutiveFailures = 0;
|
||||
@@ -251,7 +248,6 @@ class SessionTimer extends ChangeNotifier {
|
||||
_remainingSeconds = data['expires_in_seconds'] ?? _remainingSeconds;
|
||||
_quotaBytes = data['quota_bytes'] ?? _quotaBytes;
|
||||
_usedBytes = data['used_bytes'] ?? _usedBytes;
|
||||
_isThrottled = data['is_throttled'] ?? false;
|
||||
|
||||
// ── Speed calculation over the polling interval ────────────────────
|
||||
final int deltaBytes = _usedBytes - _lastUsedBytes;
|
||||
@@ -290,26 +286,6 @@ class SessionTimer extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Bonus Time ─────────────────────────────────────────────────────────────
|
||||
|
||||
/// Called after the user watches a bonus rewarded ad.
|
||||
///
|
||||
/// The actual session extension is handled server-side via the AdMob SSV
|
||||
/// callback. This method simply re-syncs so the UI picks up the new
|
||||
/// limits and un-throttled status.
|
||||
///
|
||||
/// Returns `true` if the sync succeeded, so the UI can decide whether to
|
||||
/// show a success snackbar.
|
||||
Future<bool> addBonusTime() async {
|
||||
try {
|
||||
await _syncWithHivemind();
|
||||
return _hasSyncedOnce;
|
||||
} catch (e) {
|
||||
debugPrint('Bonus-time sync error: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Stop ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Called externally (e.g. from ConnectButton) to begin tearing down.
|
||||
|
||||
@@ -77,12 +77,16 @@ class VpnConnection extends ChangeNotifier {
|
||||
switch (status.connectionState) {
|
||||
case VlessConnectionState.connected:
|
||||
_setStatus(VpnStatus.connected, 'Secured');
|
||||
break;
|
||||
case VlessConnectionState.disconnected:
|
||||
_setStatus(VpnStatus.disconnected, 'Tap to connect');
|
||||
break;
|
||||
case VlessConnectionState.connecting:
|
||||
_setStatus(VpnStatus.connecting, 'Establishing tunnel…');
|
||||
break;
|
||||
case VlessConnectionState.disconnecting:
|
||||
_setStatus(VpnStatus.disconnecting, 'Tearing down…');
|
||||
break;
|
||||
case VlessConnectionState.unknown:
|
||||
// Native backend emitted an unrecognized state — treat as error
|
||||
// only if we aren't already in a terminal state.
|
||||
@@ -90,6 +94,7 @@ class VpnConnection extends ChangeNotifier {
|
||||
_status != VpnStatus.disconnected) {
|
||||
_setStatus(VpnStatus.error, 'Connection failed');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +226,13 @@ class VpnConnection extends ChangeNotifier {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (_status == VpnStatus.connected || _status == VpnStatus.connecting) {
|
||||
try {
|
||||
_vless.stopVless();
|
||||
} catch (_) {
|
||||
// Best-effort — widget is being destroyed anyway
|
||||
}
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user