refactor(app): remove unsupported server selector state
Remove UI and provider state that does not control the authoritative tunnel destination while preserving the existing connection-health status behavior.
This commit is contained in:
1 parent
9ac236a981
commit
0a8f78b5d6
4 files changed
+12
-178
No files matched your search
@@ -1,11 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.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/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 {
|
class StatusBar extends StatelessWidget {
|
||||||
const StatusBar({super.key});
|
const StatusBar({super.key});
|
||||||
@@ -26,37 +24,12 @@ class StatusBar extends StatelessWidget {
|
|||||||
? 'Connecting…'
|
? 'Connecting…'
|
||||||
: (vpn.serverReachable ? 'Ready' : 'Offline'));
|
: (vpn.serverReachable ? 'Ready' : 'Offline'));
|
||||||
|
|
||||||
final server = context.watch<ServerList>().selected;
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
Container(
|
||||||
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:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -66,12 +39,16 @@ class StatusBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Image.asset(server.flagAsset, width: 20, height: 20),
|
Image.asset(
|
||||||
|
'assets/finland_flag_256.png',
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
const Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
server.name,
|
'Helsinki, Finland',
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.accent,
|
color: AppColors.accent,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
@@ -79,15 +56,9 @@ class StatusBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Icon(
|
|
||||||
Icons.chevron_right,
|
|
||||||
color: AppColors.textDim,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Container(
|
Container(
|
||||||
padding:
|
padding:
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ import 'package:revoltvpn/logic/ad_manager.dart';
|
|||||||
import 'package:revoltvpn/logic/app_colors.dart';
|
import 'package:revoltvpn/logic/app_colors.dart';
|
||||||
import 'package:revoltvpn/logic/connection_settings.dart';
|
import 'package:revoltvpn/logic/connection_settings.dart';
|
||||||
import 'package:revoltvpn/logic/haptic_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/session_timer.dart';
|
||||||
import 'package:revoltvpn/logic/vpn_connection.dart';
|
import 'package:revoltvpn/logic/vpn_connection.dart';
|
||||||
import 'package:revoltvpn/screens/intro.dart';
|
import 'package:revoltvpn/screens/intro.dart';
|
||||||
@@ -56,10 +55,6 @@ class ReVoltApp extends StatelessWidget {
|
|||||||
prev ?? SessionTimer(vpnConnection: vpn),
|
prev ?? SessionTimer(vpnConnection: vpn),
|
||||||
),
|
),
|
||||||
ChangeNotifierProvider(create: (_) => AdManager()),
|
ChangeNotifierProvider(create: (_) => AdManager()),
|
||||||
ChangeNotifierProvider(
|
|
||||||
create: (_) => ServerList()..init(),
|
|
||||||
lazy: false,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
title: 'ReVolt VPN',
|
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),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user