import 'dart:async'; import 'package:astral/utils/app_info.dart'; import 'package:astral/utils/up.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; // 添加 Riverpod 导入 import '../config/app_config.dart'; import '../utils/ping_util.dart'; import 'package:astral/utils/kv_state.dart'; import 'package:http/http.dart' as http; // 添加 http 包导入 import 'dart:convert'; // 添加 json 解析支持 import 'package:astral/utils/serverjs.dart'; class Pserver { final int id; final String name; final String address; final String provider; final String version; final bool isOfficialServer; final bool isTransferable; final String ip; Pserver({ required this.id, required this.name, required this.address, required this.provider, required this.version, required this.isOfficialServer, required this.isTransferable, required this.ip, }); } // 将 StatefulWidget 改为 ConsumerStatefulWidget class SettingsPage extends ConsumerStatefulWidget { const SettingsPage({super.key}); @override ConsumerState createState() => _SettingsPageState(); } final updateChecker = UpdateChecker( owner: 'ldoubil', repo: 'astral', ); // 存储服务器组列表的状态变量 // 使用 StateProvider 来管理服务器组列表状态 final pServerProvider = StateProvider>((ref) => []); // 将 State 改为 ConsumerState class _SettingsPageState extends ConsumerState { late List> _serverList; final _appConfig = AppConfig(); bool _closeToTray = false; // 添加关闭进入托盘变量 bool _pingEnabled = true; // 添加全局ping开关 // 添加高级选项变量 String _defaultProtocol = "tcp"; String _devName = ""; bool _enableEncryption = true; bool _enableIpv6 = true; int _mtu = 1380; bool _latencyFirst = false; bool _enableExitNode = false; bool _proxyForwardBySystem = false; bool _noTun = false; bool _useSmoltcp = false; String _relayNetworkWhitelist = "*"; bool _disableP2p = false; bool _relayAllPeerRpc = false; bool _disableUdpHolePunching = false; bool _multiThread = true; String _dataCompressAlgo = "None"; bool _bindDevice = true; bool _enableKcpProxy = false; bool _disableKcpInput = false; bool _disableRelayKcp = true; String serverIP = ""; // 添加 ping 相关状态 Map pingResults = {}; @override void initState() { super.initState(); // 从 Riverpod 获取服务器列表 _serverList = ref.read(serverListProvider); serverIP = _getSelectedServersString(); _closeToTray = _appConfig.closeToTray; // 初始化托盘设置 // 初始化全局ping开关 _pingEnabled = _appConfig.enablePing; // 初始化高级设置 final advancedConfig = ref.read(advancedConfigProvider); _defaultProtocol = advancedConfig['defaultProtocol'] ?? "tcp"; _devName = advancedConfig['devName'] ?? ""; _enableEncryption = advancedConfig['enableEncryption'] ?? true; _enableIpv6 = advancedConfig['enableIpv6'] ?? true; _mtu = advancedConfig['mtu'] ?? 1380; _latencyFirst = advancedConfig['latencyFirst'] ?? false; _enableExitNode = advancedConfig['enableExitNode'] ?? false; _proxyForwardBySystem = advancedConfig['proxyForwardBySystem'] ?? false; _noTun = advancedConfig['noTun'] ?? false; _useSmoltcp = advancedConfig['useSmoltcp'] ?? false; _relayNetworkWhitelist = advancedConfig['relayNetworkWhitelist'] ?? "*"; _disableP2p = advancedConfig['disableP2p'] ?? false; _relayAllPeerRpc = advancedConfig['relayAllPeerRpc'] ?? false; _disableUdpHolePunching = advancedConfig['disableUdpHolePunching'] ?? false; _multiThread = advancedConfig['multiThread'] ?? true; _dataCompressAlgo = advancedConfig['dataCompressAlgo'] ?? "None"; _bindDevice = advancedConfig['bindDevice'] ?? true; _enableKcpProxy = advancedConfig['enableKcpProxy'] ?? false; _disableKcpInput = advancedConfig['disableKcpInput'] ?? false; _disableRelayKcp = advancedConfig['disableRelayKcp'] ?? true; // 初始化 ping 状态 for (var server in _serverList) { pingResults[server['url']] = null; } // 开始 ping 所有服务器 _startPingAllServers(); } // 获取选中的服务器字符串 String _getSelectedServersString() { final selected = _serverList.where((server) => server['selected'] == true).toList(); if (selected.isEmpty && _serverList.isNotEmpty) { return _serverList.first['url']; } return selected.map((server) => server['url']).join(', '); } // 添加一个计时器变量来控制 ping 操作 Timer? _pingTimer; // 新增方法:开始 ping 所有服务器 void _startPingAllServers() { // 取消之前的计时器(如果存在) _pingTimer?.cancel(); // 创建新的计时器,使用设置的间隔时间 _pingTimer = Timer.periodic(Duration(milliseconds: 1000), (timer) { if (!mounted) { timer.cancel(); return; } if (_pingEnabled) { for (var server in _serverList) { _pingServerOnce(server['url']); } } }); } @override void dispose() { // 取消计时器 _pingTimer?.cancel(); _pingTimer = null; super.dispose(); } // 执行单次 ping 操作 Future _pingServerOnce(String server) async { final pingResult = await PingUtil.ping(server); if (mounted) { setState(() { pingResults[server] = pingResult; }); } } // 显示公共服务器列表 void _showPublicServerList(BuildContext context) { showDialog( context: context, builder: (context) { return AlertDialog( title: Row( children: [ const Icon(Icons.public), const SizedBox(width: 8), const Text('公共服务器列表'), const Spacer(), IconButton( icon: const Icon(Icons.refresh), onPressed: () { _fetchEasyTierStatus(); }, tooltip: '刷新服务器列表', ), ], ), content: SizedBox( width: double.maxFinite, // 调整高度,使其不会过高 height: MediaQuery.of(context).size.height * 0.5, child: Consumer( builder: (context, ref, child) { final publicServers = ref.watch(pServerProvider); return publicServers.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('暂无公共服务器数据'), const SizedBox(height: 16), ElevatedButton( onPressed: () { _fetchEasyTierStatus(); }, child: const Text('获取公共服务器数据'), ), ], ), ) : ListView.builder( // 修改为ListView.builder,移除separated itemCount: publicServers.length, itemBuilder: (context, index) { final server = publicServers[index]; return Column( children: [ ListTile( leading: Icon( server.isOfficialServer ? Icons.verified_user : Icons.person, color: server.isOfficialServer ? Colors.green : Colors.blue, ), title: Text(server.name), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '地址: ${server.address}', overflow: TextOverflow.ellipsis, ), Text( 'IP: ${server.ip}', overflow: TextOverflow.ellipsis, ), Row( mainAxisSize: MainAxisSize.min, children: [ Flexible( child: Chip( label: Text( server.isOfficialServer ? '官方' : '第三方', style: const TextStyle(fontSize: 10), ), backgroundColor: server .isOfficialServer ? Colors.green.withOpacity(0.2) : Colors.blue.withOpacity(0.2), visualDensity: VisualDensity.compact, labelPadding: const EdgeInsets.symmetric( horizontal: 4), ), ), const SizedBox(width: 4), Flexible( child: Chip( label: Text( server.isTransferable ? '可转发' : '不可转发', style: const TextStyle(fontSize: 10), ), backgroundColor: server .isTransferable ? Colors.orange.withOpacity(0.2) : Colors.red.withOpacity(0.2), visualDensity: VisualDensity.compact, labelPadding: const EdgeInsets.symmetric( horizontal: 4), ), ), ], ), ], ), isThreeLine: true, trailing: IconButton( icon: const Icon(Icons.add_circle), color: Colors.green, onPressed: () => _addPublicServerToList(server), tooltip: '添加到我的服务器', ), ), if (index < publicServers.length - 1) const Divider(height: 1), ], ); }, ); }, ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('关闭'), ), ], ); }, ); } // 添加公共服务器到我的服务器列表 void _addPublicServerToList(Pserver publicServer) { // 检查是否已存在相同地址的服务器 final existingServer = _serverList.firstWhere( (server) => server['url'] == publicServer.ip, orElse: () => {}, ); if (existingServer.isNotEmpty) { // 已存在相同地址的服务器 ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('服务器 ${publicServer.ip} 已存在于您的列表中'), behavior: SnackBarBehavior.floating, ), ); return; } setState(() { // 添加新服务器,默认不选中,使用IP地址而不是address _serverList.add({ 'url': publicServer.ip, 'name': publicServer.name, 'selected': false, 'tcp': true, 'udp': true, 'ws': false, 'wss': false, 'quic': false, }); _appConfig.setServerList(_serverList); // 初始化新服务器的 ping 状态 pingResults[publicServer.ip] = null; }); // 显示添加成功提示 ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('已添加服务器: ${publicServer.name}'), behavior: SnackBarBehavior.floating, action: SnackBarAction( label: '确定', onPressed: () { ScaffoldMessenger.of(context).hideCurrentSnackBar(); }, ), ), ); } // 切换全局ping状态 void _togglePingStatus(bool value) { setState(() { _pingEnabled = value; _appConfig.setEnablePing(_pingEnabled); if (!_pingEnabled) { // 如果关闭ping,清空所有结果 for (var server in _serverList) { pingResults[server['url']] = null; } } }); } // 添加服务器对话框 Future _showAddServerDialog() async { final urlController = TextEditingController(); final nameController = TextEditingController(); // 添加协议开关状态 bool tcpEnabled = true; // 默认启用TCP bool udpEnabled = true; // 默认启用UDP bool wsEnabled = false; bool wssEnabled = false; bool quicEnabled = false; final result = await showDialog>( context: context, builder: (context) => StatefulBuilder( builder: (context, setState) => AlertDialog( title: const Text('添加服务器'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: nameController, decoration: const InputDecoration( labelText: '服务器名称', hintText: '自定义名称', ), ), const SizedBox(height: 8), TextField( controller: urlController, decoration: const InputDecoration( labelText: '服务器地址', hintText: 'example.com:port', ), ), const SizedBox(height: 16), const Divider(), const Text('支持的协议', style: TextStyle(fontWeight: FontWeight.bold)), SwitchListTile( title: const Text('TCP'), value: tcpEnabled, onChanged: (value) => setState(() => tcpEnabled = value), dense: true, ), SwitchListTile( title: const Text('UDP'), value: udpEnabled, onChanged: (value) => setState(() => udpEnabled = value), dense: true, ), SwitchListTile( title: const Text('WebSocket (WS)'), value: wsEnabled, onChanged: (value) => setState(() => wsEnabled = value), dense: true, ), SwitchListTile( title: const Text('WebSocket Secure (WSS)'), value: wssEnabled, onChanged: (value) => setState(() => wssEnabled = value), dense: true, ), SwitchListTile( title: const Text('QUIC'), value: quicEnabled, onChanged: (value) => setState(() => quicEnabled = value), dense: true, ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () { if (urlController.text.isNotEmpty) { Navigator.pop(context, { 'url': urlController.text, 'name': nameController.text.isNotEmpty ? nameController.text : urlController.text, 'tcp': tcpEnabled, 'udp': udpEnabled, 'ws': wsEnabled, 'wss': wssEnabled, 'quic': quicEnabled, }); } }, child: const Text('添加'), ), ], ), ), ); if (result != null) { setState(() { // 添加新服务器,默认不选中,包含协议设置 _serverList.add({ 'url': result['url'], 'name': result['name'], 'selected': false, 'tcp': result['tcp'] ?? true, 'udp': result['udp'] ?? true, 'ws': result['ws'] ?? false, 'wss': result['wss'] ?? false, 'quic': result['quic'] ?? false, }); _appConfig.setServerList(_serverList); // 初始化新服务器的 ping 状态 pingResults[result['url']] = null; }); } } // 编辑服务器对话框 Future _showEditServerDialog(int index) async { final server = _serverList[index]; final urlController = TextEditingController(text: server['url']); final nameController = TextEditingController(text: server['name']); // 初始化协议开关状态 bool tcpEnabled = server['tcp'] ?? true; bool udpEnabled = server['udp'] ?? true; bool wsEnabled = server['ws'] ?? false; bool wssEnabled = server['wss'] ?? false; bool quicEnabled = server['quic'] ?? false; final result = await showDialog>( context: context, builder: (context) => StatefulBuilder( builder: (context, setState) => AlertDialog( title: const Text('编辑服务器'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: nameController, decoration: const InputDecoration( labelText: '服务器名称', hintText: '自定义名称', ), ), const SizedBox(height: 8), TextField( controller: urlController, decoration: const InputDecoration( labelText: '服务器地址', hintText: 'example.com:port', ), ), const SizedBox(height: 16), const Divider(), const Text('支持的协议', style: TextStyle(fontWeight: FontWeight.bold)), SwitchListTile( title: const Text('TCP'), value: tcpEnabled, onChanged: (value) => setState(() => tcpEnabled = value), dense: true, ), SwitchListTile( title: const Text('UDP'), value: udpEnabled, onChanged: (value) => setState(() => udpEnabled = value), dense: true, ), SwitchListTile( title: const Text('WebSocket (WS)'), value: wsEnabled, onChanged: (value) => setState(() => wsEnabled = value), dense: true, ), SwitchListTile( title: const Text('WebSocket Secure (WSS)'), value: wssEnabled, onChanged: (value) => setState(() => wssEnabled = value), dense: true, ), SwitchListTile( title: const Text('QUIC'), value: quicEnabled, onChanged: (value) => setState(() => quicEnabled = value), dense: true, ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () { if (urlController.text.isNotEmpty) { Navigator.pop(context, { 'url': urlController.text, 'name': nameController.text.isNotEmpty ? nameController.text : urlController.text, 'tcp': tcpEnabled, 'udp': udpEnabled, 'ws': wsEnabled, 'wss': wssEnabled, 'quic': quicEnabled, }); } }, child: const Text('保存'), ), ], ), ), ); if (result != null) { final oldUrl = server['url']; setState(() { _serverList[index] = { 'url': result['url'], 'name': result['name'], 'selected': server['selected'], 'tcp': result['tcp'] ?? true, 'udp': result['udp'] ?? true, 'ws': result['ws'] ?? false, 'wss': result['wss'] ?? false, 'quic': result['quic'] ?? false, }; _appConfig.setServerList(_serverList); // 更新 ping 状态 if (oldUrl != result['url']) { pingResults[result['url']] = pingResults[oldUrl]; pingResults.remove(oldUrl); } // 更新当前选中的服务器显示 serverIP = _getSelectedServersString(); // 使用 Riverpod 更新服务器列表 ref.read(serverListProvider.notifier).setServerList(_serverList); }); } } // 删除服务器 Future _deleteServer(int index) async { final confirm = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('确认删除'), content: const Text('确定要删除这个服务器吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('取消'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('删除'), ), ], ), ); if (confirm == true) { final server = _serverList[index]; setState(() { _serverList.removeAt(index); _appConfig.setServerList(_serverList); // 移除 ping 状态 pingResults.remove(server['url']); // 确保至少有一个服务器被选中 if (_serverList.isNotEmpty && !_serverList.any((server) => server['selected'] == true)) { _serverList.first['selected'] = true; } // 更新当前选中的服务器显示 serverIP = _getSelectedServersString(); // 使用 Riverpod 更新服务器列表 ref.read(serverListProvider.notifier).setServerList(_serverList); }); } } // 切换服务器选中状态 void _toggleServerSelection(int index) { setState(() { _serverList[index]['selected'] = !(_serverList[index]['selected'] ?? false); _appConfig.setServerList(_serverList); // 更新当前选中的服务器显示 serverIP = _getSelectedServersString(); // 使用 Riverpod 更新服务器列表 ref.read(serverListProvider.notifier).setServerList(_serverList); }); } // 添加构建 ping 显示组件的方法 Widget _buildPingWidget(String url) { final pingResult = pingResults[url]; if (!_pingEnabled) { return const Text('Ping已关闭', style: TextStyle(color: Colors.grey)); } else if (pingResult == null) { return const Text('测试中...', style: TextStyle(color: Colors.grey)); } else { return Text( '${pingResult}ms', style: TextStyle( color: pingResult < 100 ? Colors.green : (pingResult < 300 ? Colors.orange : Colors.red), ), ); } } // 添加一个方法来显示服务器支持的协议 Widget _buildProtocolChips(Map server) { List chips = []; if (server['tcp'] == true) { chips.add(Chip( label: const Text('TCP', style: TextStyle(fontSize: 10)), backgroundColor: Colors.blue.withOpacity(0.2), visualDensity: VisualDensity.compact, labelPadding: const EdgeInsets.symmetric(horizontal: 4), )); } if (server['udp'] == true) { chips.add(Chip( label: const Text('UDP', style: TextStyle(fontSize: 10)), backgroundColor: Colors.green.withOpacity(0.2), visualDensity: VisualDensity.compact, labelPadding: const EdgeInsets.symmetric(horizontal: 4), )); } if (server['ws'] == true) { chips.add(Chip( label: const Text('WS', style: TextStyle(fontSize: 10)), backgroundColor: Colors.orange.withOpacity(0.2), visualDensity: VisualDensity.compact, labelPadding: const EdgeInsets.symmetric(horizontal: 4), )); } if (server['wss'] == true) { chips.add(Chip( label: const Text('WSS', style: TextStyle(fontSize: 10)), backgroundColor: Colors.purple.withOpacity(0.2), visualDensity: VisualDensity.compact, labelPadding: const EdgeInsets.symmetric(horizontal: 4), )); } if (server['quic'] == true) { chips.add(Chip( label: const Text('QUIC', style: TextStyle(fontSize: 10)), backgroundColor: Colors.teal.withOpacity(0.2), visualDensity: VisualDensity.compact, labelPadding: const EdgeInsets.symmetric(horizontal: 4), )); } return Wrap( spacing: 4, runSpacing: 0, children: chips, ); } @override Widget build(BuildContext context) { // updateChecker.checkForUpdates(context); return ListView(padding: const EdgeInsets.all(16.0), children: [ Card( child: Column( children: [ ExpansionTile( initiallyExpanded: false, leading: const Icon(Icons.list), title: const Text('服务器列表'), children: [ ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _serverList.length, itemBuilder: (context, index) { final server = _serverList[index]; final isSelected = server['selected'] == true; return ListTile( leading: Icon( isSelected ? Icons.check_circle : Icons.circle_outlined, color: isSelected ? Colors.green : null, ), title: Row( children: [ Expanded( child: Text( server['name'], overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), _buildPingWidget(server['url']), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(server['url']), const SizedBox(height: 4), _buildProtocolChips(server), ], ), isThreeLine: true, trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.edit), onPressed: () => _showEditServerDialog(index), ), IconButton( icon: const Icon(Icons.delete), onPressed: () => _deleteServer(index), ), ], ), onTap: () => _toggleServerSelection(index), ); }, ), ListTile( leading: const Icon(Icons.add), title: const Text('添加新服务器'), onTap: _showAddServerDialog, ), // 添加公共服务器列表入口 ListTile( leading: const Icon(Icons.public), title: const Text('查看公共服务器列表'), onTap: () => _showPublicServerList(context), ), ], ), ], ), ), const SizedBox(height: 16), Card( child: Column( children: [ const ListTile( leading: Icon(Icons.settings), title: Text('应用设置'), ), SwitchListTile( title: const Text('关闭时最小化到托盘'), subtitle: const Text('关闭窗口时应用将继续在后台运行'), value: _closeToTray, onChanged: (value) { setState(() { _closeToTray = value; _appConfig.setCloseToTray(value); }); }, ), SwitchListTile( title: const Text('启用服务器Ping测试'), subtitle: const Text('定期测试所有服务器的网络延迟'), value: _pingEnabled, onChanged: _togglePingStatus, ), ], ), ), const SizedBox(height: 16), // 添加高级选项卡 Card( child: Column( children: [ ExpansionTile( leading: const Icon(Icons.tune), title: const Text('高级选项'), subtitle: const Text('调整网络和性能参数'), children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 协议设置 const ListTile( contentPadding: EdgeInsets.zero, title: Text( '协议设置', style: TextStyle(fontWeight: FontWeight.bold), ), ), DropdownButtonFormField( decoration: const InputDecoration( labelText: '默认协议', border: OutlineInputBorder(), ), value: _defaultProtocol, items: const [ DropdownMenuItem(value: 'tcp', child: Text('TCP')), DropdownMenuItem(value: 'udp', child: Text('UDP')), DropdownMenuItem(value: 'quic', child: Text('QUIC')), DropdownMenuItem( value: 'ws', child: Text('WebSocket')), DropdownMenuItem( value: 'wss', child: Text('WebSocket Secure')), ], onChanged: (value) { setState(() { _defaultProtocol = value!; ref .read(advancedConfigProvider.notifier) .setDefaultProtocol(value); }); }, ), const SizedBox(height: 16), // 设备设置 const ListTile( contentPadding: EdgeInsets.zero, title: Text( '设备设置', style: TextStyle(fontWeight: FontWeight.bold), ), ), TextField( decoration: const InputDecoration( labelText: '设备名称', hintText: '留空使用默认值', border: OutlineInputBorder(), ), controller: TextEditingController(text: _devName), onChanged: (value) { setState(() { _devName = value; ref .read(advancedConfigProvider.notifier) .setDevName(value); }); }, ), const SizedBox(height: 16), // MTU设置 Row( children: [ Expanded( child: TextField( decoration: const InputDecoration( labelText: 'MTU值', border: OutlineInputBorder(), ), keyboardType: TextInputType.number, controller: TextEditingController(text: _mtu.toString()), onChanged: (value) { final mtuValue = int.tryParse(value) ?? 1380; setState(() { _mtu = mtuValue; ref .read(advancedConfigProvider.notifier) .updateConfig('mtu', mtuValue); }); }, ), ), ], ), const SizedBox(height: 16), // 安全设置 const ListTile( contentPadding: EdgeInsets.zero, title: Text( '安全设置', style: TextStyle(fontWeight: FontWeight.bold), ), ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('启用加密'), subtitle: const Text('加密网络流量以提高安全性'), value: _enableEncryption, onChanged: (value) { setState(() { _enableEncryption = value; ref .read(advancedConfigProvider.notifier) .updateConfig('enableEncryption', value); }); }, ), // 网络设置 const ListTile( contentPadding: EdgeInsets.zero, title: Text( '网络设置', style: TextStyle(fontWeight: FontWeight.bold), ), ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('启用IPv6'), subtitle: const Text('允许IPv6网络连接'), value: _enableIpv6, onChanged: (value) { setState(() { _enableIpv6 = value; ref .read(advancedConfigProvider.notifier) .updateConfig('enableIpv6', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('优先低延迟'), subtitle: const Text('优先考虑连接延迟而非带宽'), value: _latencyFirst, onChanged: (value) { setState(() { _latencyFirst = value; ref .read(advancedConfigProvider.notifier) .updateConfig('latencyFirst', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('启用出口节点'), subtitle: const Text('允许作为网络出口节点'), value: _enableExitNode, onChanged: (value) { setState(() { _enableExitNode = value; ref .read(advancedConfigProvider.notifier) .updateConfig('enableExitNode', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('系统代理转发'), subtitle: const Text('通过系统代理转发流量'), value: _proxyForwardBySystem, onChanged: (value) { setState(() { _proxyForwardBySystem = value; ref .read(advancedConfigProvider.notifier) .updateConfig('proxyForwardBySystem', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('禁用TUN'), subtitle: const Text('不使用TUN虚拟网络接口'), value: _noTun, onChanged: (value) { setState(() { _noTun = value; ref .read(advancedConfigProvider.notifier) .updateConfig('noTun', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('使用Smoltcp'), subtitle: const Text('使用Smoltcp网络栈'), value: _useSmoltcp, onChanged: (value) { setState(() { _useSmoltcp = value; ref .read(advancedConfigProvider.notifier) .updateConfig('useSmoltcp', value); }); }, ), // 中继设置 const ListTile( contentPadding: EdgeInsets.zero, title: Text( '中继设置', style: TextStyle(fontWeight: FontWeight.bold), ), ), TextField( decoration: const InputDecoration( labelText: '中继网络白名单', hintText: '使用*表示允许所有', border: OutlineInputBorder(), ), controller: TextEditingController(text: _relayNetworkWhitelist), onChanged: (value) { setState(() { _relayNetworkWhitelist = value; ref .read(advancedConfigProvider.notifier) .updateConfig('relayNetworkWhitelist', value); }); }, ), const SizedBox(height: 16), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('禁用P2P'), subtitle: const Text('禁用点对点直接连接'), value: _disableP2p, onChanged: (value) { setState(() { _disableP2p = value; ref .read(advancedConfigProvider.notifier) .updateConfig('disableP2p', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('中继所有对等RPC'), subtitle: const Text('通过中继服务器转发所有RPC请求'), value: _relayAllPeerRpc, onChanged: (value) { setState(() { _relayAllPeerRpc = value; ref .read(advancedConfigProvider.notifier) .updateConfig('relayAllPeerRpc', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('禁用UDP打洞'), subtitle: const Text('禁用UDP NAT穿透技术'), value: _disableUdpHolePunching, onChanged: (value) { setState(() { _disableUdpHolePunching = value; ref .read(advancedConfigProvider.notifier) .updateConfig('disableUdpHolePunching', value); }); }, ), // 性能设置 const ListTile( contentPadding: EdgeInsets.zero, title: Text( '性能设置', style: TextStyle(fontWeight: FontWeight.bold), ), ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('多线程'), subtitle: const Text('启用多线程处理以提高性能'), value: _multiThread, onChanged: (value) { setState(() { _multiThread = value; ref .read(advancedConfigProvider.notifier) .updateConfig('multiThread', value); }); }, ), DropdownButtonFormField( decoration: const InputDecoration( labelText: '数据压缩算法', border: OutlineInputBorder(), ), value: _dataCompressAlgo, items: const [ DropdownMenuItem(value: 'None', child: Text('无压缩')), DropdownMenuItem(value: 'Lz4', child: Text('LZ4')), DropdownMenuItem(value: 'Zstd', child: Text('Zstd')), ], onChanged: (value) { setState(() { _dataCompressAlgo = value!; ref .read(advancedConfigProvider.notifier) .updateConfig('dataCompressAlgo', value); }); }, ), const SizedBox(height: 16), // KCP设置 const ListTile( contentPadding: EdgeInsets.zero, title: Text( 'KCP设置', style: TextStyle(fontWeight: FontWeight.bold), ), ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('绑定设备'), subtitle: const Text('将连接绑定到特定网络设备'), value: _bindDevice, onChanged: (value) { setState(() { _bindDevice = value; ref .read(advancedConfigProvider.notifier) .updateConfig('bindDevice', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('启用KCP代理'), subtitle: const Text('使用KCP协议进行代理'), value: _enableKcpProxy, onChanged: (value) { setState(() { _enableKcpProxy = value; ref .read(advancedConfigProvider.notifier) .updateConfig('enableKcpProxy', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('禁用KCP输入'), subtitle: const Text('禁止KCP协议输入'), value: _disableKcpInput, onChanged: (value) { setState(() { _disableKcpInput = value; ref .read(advancedConfigProvider.notifier) .updateConfig('disableKcpInput', value); }); }, ), SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('禁用中继KCP'), subtitle: const Text('禁用中继服务器的KCP协议'), value: _disableRelayKcp, onChanged: (value) { setState(() { _disableRelayKcp = value; ref .read(advancedConfigProvider.notifier) .updateConfig('disableRelayKcp', value); }); }, ), ], ), ), ], ), ], ), ), const SizedBox(height: 16), Card( child: Column( children: [ ListTile( leading: Icon(Icons.info), title: Text('应用版本'), subtitle: Text(AppInfoUtil.getVersion()), ), ListTile( leading: const Icon(Icons.update), title: const Text('检查更新'), onTap: () { updateChecker.checkForUpdates(context); }, ), ListTile( leading: const Icon(Icons.cloud), title: const Text('获取 EasyTier 状态'), onTap: _fetchEasyTierStatus, ), ], ), ), ]); } // 添加网络请求方法 Future _fetchEasyTierStatus() async { try { // 显示加载指示器 if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('正在获取服务器数据...')), ); } final response = await http .get(Uri.parse('https://easytier.gd.nkbpal.cn/status/easytier')); if (response.statusCode == 200) { // 请求成功,打印响应内容 print('EasyTier 状态: ${response.body}'); // 提取 window.preloadData = 和 之间的内容 try { final String responseBody = response.body; final startMarker = 'window.preloadData = '; final endMarker = ''; final startIndex = responseBody.indexOf(startMarker); final endIndex = responseBody.indexOf(endMarker, startIndex); if (startIndex != -1 && endIndex != -1) { final startDataIndex = startIndex + startMarker.length; final extractedData = responseBody.substring(startDataIndex, endIndex).trim(); print('提取的数据: $extractedData'); // 尝试解析提取的JSON数据 try { // 先将字符串解析为Map // 去除最后的分号并将单引号替换为双引号 String cleanData = extractedData .replaceAll(RegExp(r';$'), '') .replaceAll("'", '"'); Map jsonMap = json.decode(cleanData); StatusPageData? pageData = StatusPageData.fromJson(jsonMap); // 打印解析后的数据 print('解析后的数据: $pageData'); // 初始化空列表 final List pGroupList = []; if (pageData.publicGroupList.length > 1) { pageData.publicGroupList[1].monitorList.forEach((monitor) { try { List parts = monitor.name.split('/'); if (parts.length >= 4) { // 尝试从各个部分中提取IP:端口格式 String finalIp = ""; // 遍历所有部分,查找符合IP:端口或域名:端口格式的字符串 for (String part in parts) { // 检查是否符合IP:端口或域名:端口格式 bool isIpPort = RegExp(r'^(\d{1,3}\.){3}\d{1,3}(:\d+)?$') .hasMatch(part); bool isDomainPort = RegExp( r'^[a-zA-Z0-9][-a-zA-Z0-9\.]+\.[a-zA-Z]+:\d+$') .hasMatch(part); if (isIpPort || isDomainPort) { finalIp = part; break; } } // 如果没有找到,尝试查找IPv4或IPv6标记后的部分 if (finalIp.isEmpty) { for (int i = 0; i < parts.length - 1; i++) { if (parts[i] == "IPv4" || parts[i] == "IPv6" || parts[i] == "TCP" || parts[i] == "UDP") { String nextPart = parts[i + 1]; if (RegExp(r'^[a-zA-Z0-9][-a-zA-Z0-9\.]+\.[a-zA-Z]+:\d+$') .hasMatch(nextPart) || RegExp(r'^(\d{1,3}\.){3}\d{1,3}(:\d+)?$') .hasMatch(nextPart)) { finalIp = nextPart; break; } } } } // 如果仍然没有找到,使用默认值 if (finalIp.isEmpty && parts.length > 3) { finalIp = parts[3]; // 使用默认位置 } pGroupList.add(Pserver( id: monitor.id, name: monitor.name, address: parts[0], provider: parts[1], version: parts[2], isOfficialServer: true, isTransferable: true, ip: finalIp, )); } } catch (e) { print('Error parsing server data: $e'); } }); } if (pageData.publicGroupList.length > 2) { pageData.publicGroupList[2].monitorList.forEach((monitor) { try { List parts = monitor.name.split('/'); if (parts.length >= 4) { // 尝试从各个部分中提取IP:端口格式 String finalIp = ""; // 遍历所有部分,查找符合IP:端口或域名:端口格式的字符串 for (String part in parts) { // 检查是否符合IP:端口或域名:端口格式 bool isIpPort = RegExp(r'^(\d{1,3}\.){3}\d{1,3}(:\d+)?$') .hasMatch(part); bool isDomainPort = RegExp( r'^[a-zA-Z0-9][-a-zA-Z0-9\.]+\.[a-zA-Z]+:\d+$') .hasMatch(part); if (isIpPort || isDomainPort) { finalIp = part; break; } } // 如果没有找到,尝试查找IPv4或IPv6标记后的部分 if (finalIp.isEmpty) { for (int i = 0; i < parts.length - 1; i++) { if (parts[i] == "IPv4" || parts[i] == "IPv6" || parts[i] == "TCP" || parts[i] == "UDP") { String nextPart = parts[i + 1]; if (RegExp(r'^[a-zA-Z0-9][-a-zA-Z0-9\.]+\.[a-zA-Z]+:\d+$') .hasMatch(nextPart) || RegExp(r'^(\d{1,3}\.){3}\d{1,3}(:\d+)?$') .hasMatch(nextPart)) { finalIp = nextPart; break; } } } } // 如果仍然没有找到,使用默认值 if (finalIp.isEmpty && parts.length > 3) { finalIp = parts[3]; // 使用默认位置 } pGroupList.add(Pserver( id: monitor.id, name: monitor.name, address: parts[0], provider: parts[1], version: parts[2], isOfficialServer: false, isTransferable: true, ip: finalIp, )); } } catch (e) { print('Error parsing server data: $e'); } }); } if (pageData.publicGroupList.length > 3) { pageData.publicGroupList[3].monitorList.forEach((monitor) { try { List parts = monitor.name.split('/'); if (parts.length >= 4) { // 尝试从各个部分中提取IP:端口格式 String finalIp = ""; // 遍历所有部分,查找符合IP:端口或域名:端口格式的字符串 for (String part in parts) { // 检查是否符合IP:端口或域名:端口格式 bool isIpPort = RegExp(r'^(\d{1,3}\.){3}\d{1,3}(:\d+)?$') .hasMatch(part); bool isDomainPort = RegExp( r'^[a-zA-Z0-9][-a-zA-Z0-9\.]+\.[a-zA-Z]+:\d+$') .hasMatch(part); if (isIpPort || isDomainPort) { finalIp = part; break; } } // 如果没有找到,尝试查找IPv4或IPv6标记后的部分 if (finalIp.isEmpty) { for (int i = 0; i < parts.length - 1; i++) { if (parts[i] == "IPv4" || parts[i] == "IPv6" || parts[i] == "TCP" || parts[i] == "UDP") { String nextPart = parts[i + 1]; if (RegExp(r'^[a-zA-Z0-9][-a-zA-Z0-9\.]+\.[a-zA-Z]+:\d+$') .hasMatch(nextPart) || RegExp(r'^(\d{1,3}\.){3}\d{1,3}(:\d+)?$') .hasMatch(nextPart)) { finalIp = nextPart; break; } } } } // 如果仍然没有找到,使用默认值 if (finalIp.isEmpty && parts.length > 3) { finalIp = parts[3]; // 使用默认位置 } pGroupList.add(Pserver( id: monitor.id, name: monitor.name, address: parts[0], provider: parts[1], version: parts[2], isOfficialServer: false, isTransferable: false, ip: finalIp, )); } } catch (e) { print('Error parsing server data: $e'); } }); } // 更新状态 ref.read(pServerProvider.notifier).state = pGroupList; // 显示成功提示 if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(pGroupList.isEmpty ? '未找到可用的服务器数据' : '成功获取并解析 ${pGroupList.length} 个服务器数据'), ), ); } } catch (e) { print('JSON 解析错误: $e'); // 确保状态被设置为空列表,而不是null ref.read(pServerProvider.notifier).state = []; if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('数据解析失败: $e')), ); } } } else { print('未找到目标数据标记'); // 确保状态被设置为空列表 ref.read(pServerProvider.notifier).state = []; if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('未找到目标数据标记')), ); } } } catch (e) { print('数据提取错误: $e'); // 确保状态被设置为空列表 ref.read(pServerProvider.notifier).state = []; if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('数据提取错误: $e')), ); } } } else { // 请求失败 print('请求失败,状态码: ${response.statusCode}'); // 确保状态被设置为空列表 ref.read(pServerProvider.notifier).state = []; if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('获取失败,状态码: ${response.statusCode}')), ); } } } catch (e) { // 捕获网络错误 print('网络请求错误: $e'); // 确保状态被设置为空列表 ref.read(pServerProvider.notifier).state = []; if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('网络请求错误: $e')), ); } } } }