refactor(app): remove unsupported server selector state #6

Merged
Naveax merged 1 commits from pr/remove-unsupported-server-selector into main 2026-09-06 11:18:28 +03:00
4 changed files with 12 additions and 178 deletions

No files matched your search

+12 -41
View File
@@ -1,11 +1,9 @@
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';
import 'package:revoltvpn/logic/app_colors.dart';
import 'package:revoltvpn/logic/session_timer.dart';
import 'package:revoltvpn/logic/vpn_connection.dart';
class StatusBar extends StatelessWidget {
const StatusBar({super.key});
@@ -26,37 +24,12 @@ class StatusBar extends StatelessWidget {
? 'Connecting…'
: (vpn.serverReachable ? 'Ready' : 'Offline'));
final server = context.watch<ServerList>().selected;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
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(
Container(
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
decoration: BoxDecoration(
@@ -66,12 +39,16 @@ class StatusBar extends StatelessWidget {
),
child: Row(
children: [
Image.asset(server.flagAsset, width: 20, height: 20),
Image.asset(
'assets/finland_flag_256.png',
width: 20,
height: 20,
),
const SizedBox(width: 8),
Expanded(
const Expanded(
child: Text(
server.name,
style: const TextStyle(
'Helsinki, Finland',
style: TextStyle(
color: AppColors.accent,
fontWeight: FontWeight.w600,
fontSize: 13,
@@ -79,15 +56,9 @@ class StatusBar extends StatelessWidget {
),
),
),
const Icon(
Icons.chevron_right,
color: AppColors.textDim,
size: 20,
),
],
),
),
),
const SizedBox(height: 8),
Container(
padding:
-69
View File
@@ -1,69 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
// ── lib/logic/server_list.dart ──────────────────────────────────────────────
// Server data model and ChangeNotifier — shared by StatusBar (shows current
// server name/flag) and SelectionScreen (lets user pick a server).
//
// Each server is defined by its tunnel IP/port. Reality credentials (public
// key, shortId) come from /session/status per session; only the transport
// parameters live in AppConfig.
//
// When multi-server ships:
// - _all becomes a fetched list (from /api/servers or bundled config)
// - SelectionScreen shows multiple rows
// - select() triggers a disconnect/reconnect cycle if the tunnel is active
class ServerInfo {
final String id;
final String name;
final String flagAsset;
final String ip;
final int port;
const ServerInfo({
required this.id,
required this.name,
required this.flagAsset,
required this.ip,
required this.port,
});
}
class ServerList extends ChangeNotifier {
static const _all = [
ServerInfo(
id: 'finland',
name: 'Helsinki, Finland',
flagAsset: 'assets/finland_flag_256.png',
ip: '204.168.246.88',
port: 443,
),
];
int _selectedIndex = 0;
List<ServerInfo> get all => _all;
int get selectedIndex => _selectedIndex;
ServerInfo get selected => _all[_selectedIndex];
// Loads persisted selection from SharedPreferences.
// Fire-and-forget — UI starts with default, updates when prefs load.
Future<void> init() async {
final prefs = await SharedPreferences.getInstance();
final saved = prefs.getInt('selected_server_index') ?? 0;
if (saved >= 0 && saved < _all.length && saved != _selectedIndex) {
_selectedIndex = saved;
notifyListeners();
}
}
// Switches to a different server. Persists the choice.
Future<void> select(int index) async {
if (index == _selectedIndex || index < 0 || index >= _all.length) return;
_selectedIndex = index;
notifyListeners();
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('selected_server_index', index);
}
}
-5
View File
@@ -7,7 +7,6 @@ import 'package:revoltvpn/logic/ad_manager.dart';
import 'package:revoltvpn/logic/app_colors.dart';
import 'package:revoltvpn/logic/connection_settings.dart';
import 'package:revoltvpn/logic/haptic_settings.dart';
import 'package:revoltvpn/logic/server_list.dart';
import 'package:revoltvpn/logic/session_timer.dart';
import 'package:revoltvpn/logic/vpn_connection.dart';
import 'package:revoltvpn/screens/intro.dart';
@@ -56,10 +55,6 @@ class ReVoltApp extends StatelessWidget {
prev ?? SessionTimer(vpnConnection: vpn),
),
ChangeNotifierProvider(create: (_) => AdManager()),
ChangeNotifierProvider(
create: (_) => ServerList()..init(),
lazy: false,
),
],
child: MaterialApp(
title: 'ReVolt VPN',
@@ -1,63 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:revoltvpn/logic/app_colors.dart';
import 'package:revoltvpn/logic/server_list.dart';
// ── lib/screens/server_selector/selection_screen.dart ──────────────────────
// Server picker — reads the server list from the ServerList provider.
// Each row shows a flag + city name. Tapping a row persists the choice
// and pops back. No latency measurement — the app runs inside a Reality
// tunnel and must not emit separate probe traffic.
class SelectionScreen extends StatelessWidget {
const SelectionScreen({super.key});
@override
Widget build(BuildContext context) {
final serverList = context.watch<ServerList>();
return Scaffold(
backgroundColor: AppColors.bgDeep,
appBar: AppBar(
backgroundColor: AppColors.bgSurface,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: AppColors.textWhite),
onPressed: () => Navigator.of(context).pop(),
),
title: const Text(
'Select Server',
style: TextStyle(
color: AppColors.textWhite,
fontWeight: FontWeight.w600,
),
),
),
body: ListView.builder(
itemCount: serverList.all.length,
itemBuilder: (context, index) {
final server = serverList.all[index];
final isSelected = index == serverList.selectedIndex;
return ListTile(
leading: Image.asset(server.flagAsset, width: 28, height: 28),
title: Text(server.name,
style: TextStyle(
color: isSelected ? AppColors.accent : AppColors.textWhite,
fontWeight: FontWeight.w600,
)),
trailing: isSelected
? const Icon(Icons.check, color: AppColors.accent)
: null,
onTap: () {
serverList.select(index);
Navigator.of(context).pop();
},
contentPadding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
);
},
),
);
}
}