User-Agent spoofed to Chrome on Android (was Dart/3.x). Domain renamed to userevolt.app. Branding to Revolt VPN. Removed duplicate notification, patched flutter_vless for custom icon + dark background. Merged 5 disconnect paths into single idempotent gate, fixed stopVless timeout silently lying about state. Removed kDebugMode guard from AdMob bypass.
128 lines
5.2 KiB
Dart
128 lines
5.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:revoltvpn/logic/app_colors.dart';
|
|
import 'package:revoltvpn/logic/vpn_connection.dart';
|
|
import 'package:revoltvpn/logic/session_timer.dart';
|
|
import 'package:revoltvpn/logic/server_list.dart';
|
|
import 'package:revoltvpn/components/online_dot.dart';
|
|
import 'package:revoltvpn/screens/server_selector/selection_screen.dart';
|
|
|
|
// ── lib/components/status_bar.dart ──────────────────────────────────────────
|
|
// Two-card layout at the bottom of the main screen.
|
|
//
|
|
// Top card: server location from ServerList provider (flag + city).
|
|
// Tappable → opens server selector. Always visible.
|
|
// Bottom card: connection status (health dot + label + lock icon).
|
|
//
|
|
// Separated into two rows — no more RenderFlex overflow and ready for
|
|
// multi-server picker.
|
|
|
|
class StatusBar extends StatelessWidget {
|
|
const StatusBar({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Consumer2<VpnConnection, SessionTimer>(
|
|
builder: (context, vpn, timer, _) {
|
|
final isConnected = vpn.status == VpnStatus.connected;
|
|
final isConnecting = vpn.status == VpnStatus.connecting;
|
|
final serverHealthy =
|
|
vpn.serverReachable || (isConnected && timer.hasSyncedOnce);
|
|
|
|
final statusLabel = isConnected
|
|
? (timer.hasSyncedOnce ? 'Online' : 'Syncing…')
|
|
: (isConnecting
|
|
? 'Connecting…'
|
|
: (vpn.serverReachable ? 'Ready' : 'Offline'));
|
|
|
|
// Read from the ServerList provider — the source of truth for
|
|
// which server is selected and what it looks like.
|
|
final server = context.watch<ServerList>().selected;
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// ── Server location ──────────────────────────────────────────
|
|
GestureDetector(
|
|
onTap: () {
|
|
Navigator.of(context).push(
|
|
PageRouteBuilder(
|
|
transitionDuration: const Duration(milliseconds: 300),
|
|
pageBuilder: (_, __, ___) => const SelectionScreen(),
|
|
transitionsBuilder: (_, animation, __, child) {
|
|
return SlideTransition(
|
|
position: Tween<Offset>(
|
|
begin: const Offset(1.0, 0.0),
|
|
end: Offset.zero,
|
|
).animate(CurvedAnimation(
|
|
parent: animation,
|
|
curve: Curves.easeOut,
|
|
)),
|
|
child: child,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
child: Container(
|
|
padding:
|
|
const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.bgCard,
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(color: AppColors.slate15),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Image.asset(server.flagAsset, width: 20, height: 20),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Text(server.name,
|
|
style: const TextStyle(
|
|
color: AppColors.accent,
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 13,
|
|
letterSpacing: 0.5,
|
|
)),
|
|
),
|
|
const Icon(Icons.chevron_right,
|
|
color: AppColors.textDim, size: 20),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 8),
|
|
|
|
// ── Connection status ────────────────────────────────────────
|
|
Container(
|
|
padding:
|
|
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.bgCard,
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(color: AppColors.slate15),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
OnlineDot(
|
|
isOnline: serverHealthy,
|
|
label: statusLabel,
|
|
),
|
|
const Spacer(),
|
|
if (isConnected)
|
|
const Icon(Icons.lock,
|
|
color: AppColors.green50, size: 14),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|