1. 将原有的Provider状态管理替换为Riverpod,提升状态管理效率

2. 重构AppConfig类,使用Hive进行持久化存储
3. 新增AdvancedConfig类,用于管理高级配置项
4. 优化服务器列表和节点状态的管理逻辑
5. 添加多个Provider来管理不同模块的状态
6. 更新依赖项,添加Riverpod及相关依赖
This commit is contained in:
会做饭的二哈
2025-03-18 16:28:59 +08:00
parent ca49264ad6
commit 01a4d1a81e
18 changed files with 3857 additions and 826 deletions
+3 -3
View File
@@ -4,7 +4,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:system_tray/system_tray.dart';
import 'dart:io';
import 'screens/Home.dart';
import 'config/themeconfiguration.dart';
import 'config/themeconfiguration.dart' as theme_config;
import 'config/app_config.dart';
// 定义应用程序的主要StatefulWidget
@@ -114,7 +114,7 @@ class _MyAppState extends State<MyApp> {
],
// Insert this line
supportedLocales: const [Locale("zh", "CN"), Locale("en", "US")],
theme: ThemeConfig.getLightTheme(
theme: theme_config.ThemeConfig.getLightTheme(
useMaterial3: useMaterial3,
seedColor: _seedColor,
).copyWith(
@@ -124,7 +124,7 @@ class _MyAppState extends State<MyApp> {
primaryTextTheme: Typography.material2021().black.apply(
fontFamily: 'MiSans',
)),
darkTheme: ThemeConfig.getDarkTheme(
darkTheme: theme_config.ThemeConfig.getDarkTheme(
useMaterial3: useMaterial3,
seedColor: _seedColor,
).copyWith(
+805 -230
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -3,9 +3,9 @@ import 'package:astral/src/rust/frb_generated.dart';
import 'package:window_manager/window_manager.dart';
import 'app.dart';
import 'config/windowconfiguration.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'config/app_config.dart';
import 'utils/kv_state.dart';
import 'package:provider/provider.dart'; // 添加这一行
import 'package:astral/utils/app_info.dart';
Future<void> main() async {
@@ -19,8 +19,7 @@ Future<void> main() async {
// 初始化应用信息
await RustLib.init();
runApp(
ChangeNotifierProvider(
create: (context) => KM(),
ProviderScope(
child: const MyApp(),
),
);
+162 -94
View File
@@ -1,13 +1,16 @@
// 导入必要的包
import 'dart:convert';
import 'package:astral/config/app_config.dart';
import 'package:astral/src/rust/api/simple.dart';
import 'package:astral/src/rust/frb_generated.dart';
import 'package:astral/utils/kv_state.dart';
import 'package:astral/utils/app_info.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'dart:async';
import 'package:provider/provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; // 替换 provider 导入
import '../widgets/card.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import '../utils/runin.dart';
@@ -31,7 +34,7 @@ String _intToIpv4String(int addr) {
/// 首页组件
/// 用于显示应用的主页面,包含主题切换和问候功能
class HomePage extends StatefulWidget {
class HomePage extends ConsumerStatefulWidget {
// 主题模式切换回调函数
final Function toggleThemeMode;
// 主题色更改回调函数
@@ -48,10 +51,10 @@ class HomePage extends StatefulWidget {
});
@override
State<HomePage> createState() => _HomePageState();
ConsumerState<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
class _HomePageState extends ConsumerState<HomePage> {
int connectionTimeoutCounter = 0;
// 当前连接状态
ConnectionState _connectionState = ConnectionState.notStarted;
@@ -74,6 +77,7 @@ class _HomePageState extends State<HomePage> {
bool _isAutoIP = true; // 只用于控制IP自动/手动模式
List<String> Serverip = [""];
List<ServerConfig> Serveripz = [];
int _uploadBytes = 0;
int _downloadBytes = 0;
int _lastUploadBytes = 0;
@@ -129,32 +133,32 @@ class _HomePageState extends State<HomePage> {
void _onVirtualIPFocusChange() {
if (!_virtualIPFocusNode.hasFocus && !_isAutoIP) {
// 当失去焦点且不是自动IP模式时更新值
Provider.of<KM>(context, listen: false).virtualIP =
_virtualIPController.text;
ref
.read(virtualIPProvider.notifier)
.setVirtualIP(_virtualIPController.text);
}
}
// 添加用户名焦点变化监听方法
void _onUsernameFocusChange() {
if (!_usernameControllerFocusNode.hasFocus) {
Provider.of<KM>(context, listen: false).username =
_usernameController.text;
ref.read(usernameProvider.notifier).setUsername(_usernameController.text);
}
}
// 添加房间名焦点变化监听方法
void _onRoomNameFocusChange() {
if (!_roomNameControllerFocusNode.hasFocus) {
Provider.of<KM>(context, listen: false).roomName =
_roomNameController.text;
ref.read(roomNameProvider.notifier).setRoomName(_roomNameController.text);
}
}
// 添加房间密码焦点变化监听方法
void _onRoomPasswordFocusChange() {
if (!_roomPasswordControllerFocusNode.hasFocus) {
Provider.of<KM>(context, listen: false).roomPassword =
_roomPasswordController.text;
ref
.read(roomPasswordProvider.notifier)
.setRoomPassword(_roomPasswordController.text);
}
}
@@ -186,19 +190,75 @@ class _HomePageState extends State<HomePage> {
}
void toggleRunning() {
final km = Provider.of<KM>(context, listen: false);
setState(() {
isRunning = !isRunning;
if (isRunning) {
// 切换到连接中状态
_connectionState = ConnectionState.connecting;
//利用 Serveripz 重组
List<String> ssServerip = [];
print(ssServerip);
for (var item in Serveripz) {
if (item.tcp) {
ssServerip.add("tcp://" + item.url);
}
if (item.udp) {
ssServerip.add("udp://" + item.url);
}
if (item.ws) {
ssServerip.add("ws://" + item.url);
}
if (item.wss) {
ssServerip.add("wss://" + item.url);
}
if (item.quic) {
ssServerip.add("quic://" + item.url);
}
}
// 复制
createServer(
username: username,
enableDhcp: _isAutoIP,
specifiedIp: publicIP,
roomName: roomName,
roomPassword: roomPassword,
severurl: Serverip);
severurl: ssServerip,
flag: FlagsC(
defaultProtocol: ref.read(advancedConfigProvider)['defaultProtocol'] ??
"tcp",
devName: ref.read(advancedConfigProvider)['devName'] ?? "",
enableEncryption:
ref.read(advancedConfigProvider)['enableEncryption'] ??
true,
enableIpv6:
ref.read(advancedConfigProvider)['enableIpv6'] ?? true,
mtu: ref.read(advancedConfigProvider)['mtu'] ?? 1380,
multiThread:
ref.read(advancedConfigProvider)['multiThread'] ?? true,
latencyFirst:
ref.read(advancedConfigProvider)['latencyFirst'] ?? false,
enableExitNode:
ref.read(advancedConfigProvider)['enableExitNode'] ?? false,
noTun: ref.read(advancedConfigProvider)['noTun'] ?? false,
useSmoltcp:
ref.read(advancedConfigProvider)['useSmoltcp'] ?? false,
relayNetworkWhitelist:
ref.read(advancedConfigProvider)['relayNetworkWhitelist'] ??
"*",
disableP2P:
ref.read(advancedConfigProvider)['disableP2p'] ?? false,
relayAllPeerRpc:
ref.read(advancedConfigProvider)['relayAllPeerRpc'] ??
false,
disableUdpHolePunching:
ref.read(advancedConfigProvider)['disableUdpHolePunching'] ?? false,
dataCompressAlgo: ref.read(advancedConfigProvider)['dataCompressAlgo'] ?? "None",
bindDevice: ref.read(advancedConfigProvider)['bindDevice'] ?? true,
enableKcpProxy: ref.read(advancedConfigProvider)['enableKcpProxy'] ?? false,
disableKcpInput: ref.read(advancedConfigProvider)['disableKcpInput'] ?? false,
disableRelayKcp: ref.read(advancedConfigProvider)['disableRelayKcp'] ?? true,
proxyForwardBySystem: ref.read(advancedConfigProvider)['proxyForwardBySystem'] ?? false));
// 不再使用固定延迟模拟连接成功,而是通过定时检查IP来确定连接状态
timer = Timer.periodic(const Duration(seconds: 1), (timer) async {
@@ -213,8 +273,7 @@ class _HomePageState extends State<HomePage> {
// 获取网络状态
final networkStatus = await getNetworkStatus();
final km = Provider.of<KM>(context, listen: false);
km.nodes = networkStatus.nodes;
ref.read(nodesProvider.notifier).setNodes(networkStatus.nodes);
// 更新网络流量数据
_updateNetworkStats(networkStatus.nodes);
@@ -223,7 +282,7 @@ class _HomePageState extends State<HomePage> {
if (version != null) {
String ipStr = _intToIpv4String(version);
if (publicIP != ipStr) {
km.virtualIP = ipStr;
ref.read(virtualIPProvider.notifier).setVirtualIP(ipStr);
}
// 如果当前状态还是连接中,则更新为已连接
@@ -245,8 +304,8 @@ class _HomePageState extends State<HomePage> {
});
closeAllServer();
// 清空玩家列表数据
Provider.of<KM>(context, listen: false).nodes = [];
// 清空玩家列表数据
ref.read(nodesProvider.notifier).setNodes([]);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
@@ -269,13 +328,12 @@ class _HomePageState extends State<HomePage> {
runningTime += const Duration(seconds: 1);
});
});
// 移除原来的Future.delayed模拟连接成功的代码
} else {
// 停止时重置状态
_connectionState = ConnectionState.notStarted;
closeAllServer();
// 清空玩家列表数据
Provider.of<KM>(context, listen: false).nodes = [];
ref.read(nodesProvider.notifier).setNodes([]);
timer?.cancel();
runningTime = Duration.zero;
// 重置网络统计数据
@@ -285,7 +343,6 @@ class _HomePageState extends State<HomePage> {
_lastDownloadBytes = 0;
uploadSpeed = 0;
downloadSpeed = 0;
//connectionTimeoutCounter
}
});
}
@@ -296,7 +353,7 @@ class _HomePageState extends State<HomePage> {
int totalUploadBytes = 0;
int totalDownloadBytes = 0;
String myIP = Provider.of<KM>(context, listen: false).virtualIP;
String myIP = ref.read(virtualIPProvider);
// 查找本机节点
for (var node in nodes) {
@@ -343,22 +400,22 @@ class _HomePageState extends State<HomePage> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
final km = Provider.of<KM>(context);
// 使用 Riverpod 读取数据
_roomNameController.value = TextEditingValue(
text: km.roomName,
text: ref.read(roomNameProvider),
selection: _roomNameController.selection,
);
_roomPasswordController.value = TextEditingValue(
text: km.roomPassword,
text: ref.read(roomPasswordProvider),
selection: _roomPasswordController.selection,
);
_usernameController.value = TextEditingValue(
text: km.username,
text: ref.read(usernameProvider),
selection: _usernameController.selection,
);
// 添加虚拟IP控制器的值同步
_virtualIPController.value = TextEditingValue(
text: km.virtualIP,
text: ref.read(virtualIPProvider),
selection: _virtualIPController.selection,
);
}
@@ -366,15 +423,17 @@ class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
publicIP = Provider.of<KM>(context).virtualIP;
_isAutoIP = Provider.of<KM>(context).dynamicIP; // 更新自动IP状态
//我的房间
roomName = Provider.of<KM>(context).roomName;
//我的密码
roomPassword = Provider.of<KM>(context).roomPassword;
//我的用户名
username = Provider.of<KM>(context).username;
Serverip = Provider.of<KM>(context).serverIP;
// 使用 Riverpod 读取数据
publicIP = ref.watch(virtualIPProvider);
_isAutoIP = ref.watch(dynamicIPProvider);
roomName = ref.watch(roomNameProvider);
roomPassword = ref.watch(roomPasswordProvider);
username = ref.watch(usernameProvider);
Serverip = ref.watch(serverIPProvider);
// 从 selectedServerProvider 获取服务器配置列表
final serverConfigs =
ref.watch(selectedServerProvider) as List<ServerConfig>;
Serveripz = serverConfigs;
// 使用 LayoutBuilder 来处理布局变化,同时保留状态
return Scaffold(
@@ -576,53 +635,57 @@ class _HomePageState extends State<HomePage> {
// 添加服务器列表卡片
Widget _buildServerListCard(ColorScheme colorScheme) {
final km = Provider.of<KM>(context);
// 直接使用 serverIP 列表,而不是尝试访问 serverList
final serverUrls = km.serverIP;
return Consumer(
builder: (context, ref, child) {
// 直接使用 serverIP 列表
final serverUrls = ref.watch(serverIPProvider);
return FloatingCard(
colorScheme: colorScheme,
maxWidth: 600,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题栏
Row(
return FloatingCard(
colorScheme: colorScheme,
maxWidth: 600,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.dns, color: colorScheme.primary, size: 22),
const SizedBox(width: 8),
const Text('当前服务器',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
// 标题栏
Row(
children: [
Icon(Icons.dns, color: colorScheme.primary, size: 22),
const SizedBox(width: 8),
const Text('当前服务器',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
],
),
const SizedBox(height: 16),
// 当前选中的服务器
Wrap(
spacing: 8,
runSpacing: 8,
children: serverUrls.isEmpty ||
(serverUrls.length == 1 && serverUrls[0].isEmpty)
? [
Chip(
avatar: Icon(Icons.info_outline,
size: 16, color: colorScheme.error),
label: const Text('未选择服务器'),
backgroundColor:
colorScheme.errorContainer.withOpacity(0.3),
)
]
: serverUrls
.map((url) => Chip(
avatar: Icon(Icons.dns,
size: 16, color: colorScheme.primary),
label: Text(url),
backgroundColor: colorScheme.surfaceVariant,
))
.toList(),
),
],
),
const SizedBox(height: 16),
// 当前选中的服务器
Wrap(
spacing: 8,
runSpacing: 8,
children: serverUrls.isEmpty ||
(serverUrls.length == 1 && serverUrls[0].isEmpty)
? [
Chip(
avatar: Icon(Icons.info_outline,
size: 16, color: colorScheme.error),
label: const Text('未选择服务器'),
backgroundColor:
colorScheme.errorContainer.withOpacity(0.3),
)
]
: serverUrls
.map((url) => Chip(
avatar: Icon(Icons.dns,
size: 16, color: colorScheme.primary),
label: Text(url),
backgroundColor: colorScheme.surfaceVariant,
))
.toList(),
),
],
),
);
},
);
}
@@ -716,8 +779,7 @@ class _HomePageState extends State<HomePage> {
// 优化用户信息卡片
Widget _buildUserInfoCard(ColorScheme colorScheme) {
final km = Provider.of<KM>(context, listen: false);
final isValidIP = _isAutoIP || _isValidIPv4(km.virtualIP);
final isValidIP = _isAutoIP || _isValidIPv4(ref.watch(virtualIPProvider));
return FloatingCard(
colorScheme: colorScheme,
@@ -762,8 +824,9 @@ class _HomePageState extends State<HomePage> {
enabled: _connectionState != ConnectionState.connected,
onEditingComplete: () {
// 改为完成编辑时更新
Provider.of<KM>(context, listen: false).username =
_usernameController.text;
ref
.read(usernameProvider.notifier)
.setUsername(_usernameController.text);
},
decoration: InputDecoration(
labelText: '用户名',
@@ -789,8 +852,9 @@ class _HomePageState extends State<HomePage> {
onEditingComplete: () {
// 添加完成编辑回调
if (!_isAutoIP) {
Provider.of<KM>(context, listen: false).virtualIP =
_virtualIPController.text;
ref
.read(virtualIPProvider.notifier)
.setVirtualIP(_virtualIPController.text);
}
},
decoration: InputDecoration(
@@ -812,10 +876,14 @@ class _HomePageState extends State<HomePage> {
setState(() {
_isAutoIP = value;
});
km.dynamicIP = value;
ref
.read(dynamicIPProvider.notifier)
.setDynamicIP(value);
// 切换模式时同步最新值
if (!value) {
km.virtualIP = _virtualIPController.text;
ref
.read(virtualIPProvider.notifier)
.setVirtualIP(_virtualIPController.text);
}
}
: null,
@@ -846,7 +914,6 @@ class _HomePageState extends State<HomePage> {
// 优化房间信息卡片
Widget _buildRoomInfoCard(ColorScheme colorScheme) {
final km = Provider.of<KM>(context, listen: false);
return FloatingCard(
colorScheme: colorScheme,
maxWidth: 600,
@@ -890,8 +957,9 @@ class _HomePageState extends State<HomePage> {
enabled: _connectionState != ConnectionState.connected,
onEditingComplete: () {
// 改为完成编辑时更新
Provider.of<KM>(context, listen: false).roomName =
_roomNameController.text;
ref
.read(roomNameProvider.notifier)
.setRoomName(_roomNameController.text);
},
decoration: InputDecoration(
labelText: '房间名称',
@@ -908,9 +976,9 @@ class _HomePageState extends State<HomePage> {
focusNode: _roomPasswordControllerFocusNode, // 添加焦点节点
enabled: _connectionState != ConnectionState.connected,
onEditingComplete: () {
// 改为完成编辑时更新
Provider.of<KM>(context, listen: false).roomPassword =
_roomPasswordController.text;
ref
.read(roomPasswordProvider.notifier)
.setRoomPassword(_roomPasswordController.text);
},
obscureText: true,
decoration: InputDecoration(
+15 -12
View File
@@ -3,7 +3,7 @@ import 'package:flutter/services.dart'; // 添加这一行导入剪贴板服务
import 'package:astral/utils/kv_state.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; // 替换 provider 导入
import '../widgets/card.dart';
/// 玩家信息模型类
@@ -37,14 +37,17 @@ class PlayerInfo {
/// 房间页面组件
/// 用于显示所有玩家的信息
class RoomPage extends StatefulWidget {
class RoomPage extends ConsumerStatefulWidget {
// 修改为 ConsumerStatefulWidget
const RoomPage({super.key});
@override
State<RoomPage> createState() => _RoomPageState();
ConsumerState<RoomPage> createState() =>
_RoomPageState(); // 修改为 ConsumerState
}
class _RoomPageState extends State<RoomPage> {
class _RoomPageState extends ConsumerState<RoomPage> {
// 修改为 ConsumerState
List<PlayerInfo> players = [];
List<PlayerInfo> filteredPlayers = []; // 添加过滤后的玩家列表
bool isLoading = true;
@@ -88,6 +91,7 @@ class _RoomPageState extends State<RoomPage> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
// 使用 Riverpod 监听节点数据
return Scaffold(
appBar: AppBar(
@@ -109,11 +113,10 @@ class _RoomPageState extends State<RoomPage> {
),
],
),
body: Consumer<KM>(
builder: (context, km, child) {
// 当 KM 更新时,这个 builder 会被重新调用
body: Builder(
builder: (context) {
// 异步处理数据
_processNodeData(km);
_processNodeData();
if (isLoading) {
return Center(
@@ -203,9 +206,9 @@ class _RoomPageState extends State<RoomPage> {
}
// 处理节点数据 - 合并了原来的两个相似方法
Future<void> _processNodeData(KM km) async {
Future<void> _processNodeData() async {
try {
final nodes = await km.nodes; // 获取最新的节点信息
final nodes = await ref.read(nodesProvider); // 获取最新的节点信息
// 将节点数据转换为PlayerInfo对象
List<PlayerInfo> nodePlayerInfos = [];
@@ -216,8 +219,8 @@ class _RoomPageState extends State<RoomPage> {
int downloadSpeed = 0;
int sentPackets = 0;
int receivedPackets = 0;
String connectionType =
_mapConnectionType(node.cost, node.ipv4, km.virtualIP);
String connectionType = _mapConnectionType(
node.cost, node.ipv4, ref.read(virtualIPProvider));
// 如果有连接信息,计算网络统计数据
if (node.connections.isNotEmpty) {
+1399 -203
View File
File diff suppressed because it is too large Load Diff
+101 -2
View File
@@ -37,14 +37,16 @@ Future<void> createServer(
required String specifiedIp,
required String roomName,
required String roomPassword,
required List<String> severurl}) =>
required List<String> severurl,
required FlagsC flag}) =>
RustLib.instance.api.crateApiSimpleCreateServer(
username: username,
enableDhcp: enableDhcp,
specifiedIp: specifiedIp,
roomName: roomName,
roomPassword: roomPassword,
severurl: severurl);
severurl: severurl,
flag: flag);
Future<void> closeAllServer() =>
RustLib.instance.api.crateApiSimpleCloseAllServer();
@@ -63,6 +65,103 @@ abstract class PeerRoutePair implements RustOpaqueInterface {}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Route>>
abstract class Route implements RustOpaqueInterface {}
class FlagsC {
final String defaultProtocol;
final String devName;
final bool enableEncryption;
final bool enableIpv6;
final int mtu;
final bool latencyFirst;
final bool enableExitNode;
final bool noTun;
final bool useSmoltcp;
final String relayNetworkWhitelist;
final bool disableP2P;
final bool relayAllPeerRpc;
final bool disableUdpHolePunching;
/// string ipv6_listener = 14; \[deprecated = true\]; use -l udp://\[::\]:12345 instead
final bool multiThread;
final int dataCompressAlgo;
final bool bindDevice;
final bool enableKcpProxy;
final bool disableKcpInput;
final bool disableRelayKcp;
final bool proxyForwardBySystem;
const FlagsC({
required this.defaultProtocol,
required this.devName,
required this.enableEncryption,
required this.enableIpv6,
required this.mtu,
required this.latencyFirst,
required this.enableExitNode,
required this.noTun,
required this.useSmoltcp,
required this.relayNetworkWhitelist,
required this.disableP2P,
required this.relayAllPeerRpc,
required this.disableUdpHolePunching,
required this.multiThread,
required this.dataCompressAlgo,
required this.bindDevice,
required this.enableKcpProxy,
required this.disableKcpInput,
required this.disableRelayKcp,
required this.proxyForwardBySystem,
});
@override
int get hashCode =>
defaultProtocol.hashCode ^
devName.hashCode ^
enableEncryption.hashCode ^
enableIpv6.hashCode ^
mtu.hashCode ^
latencyFirst.hashCode ^
enableExitNode.hashCode ^
noTun.hashCode ^
useSmoltcp.hashCode ^
relayNetworkWhitelist.hashCode ^
disableP2P.hashCode ^
relayAllPeerRpc.hashCode ^
disableUdpHolePunching.hashCode ^
multiThread.hashCode ^
dataCompressAlgo.hashCode ^
bindDevice.hashCode ^
enableKcpProxy.hashCode ^
disableKcpInput.hashCode ^
disableRelayKcp.hashCode ^
proxyForwardBySystem.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is FlagsC &&
runtimeType == other.runtimeType &&
defaultProtocol == other.defaultProtocol &&
devName == other.devName &&
enableEncryption == other.enableEncryption &&
enableIpv6 == other.enableIpv6 &&
mtu == other.mtu &&
latencyFirst == other.latencyFirst &&
enableExitNode == other.enableExitNode &&
noTun == other.noTun &&
useSmoltcp == other.useSmoltcp &&
relayNetworkWhitelist == other.relayNetworkWhitelist &&
disableP2P == other.disableP2P &&
relayAllPeerRpc == other.relayAllPeerRpc &&
disableUdpHolePunching == other.disableUdpHolePunching &&
multiThread == other.multiThread &&
dataCompressAlgo == other.dataCompressAlgo &&
bindDevice == other.bindDevice &&
enableKcpProxy == other.enableKcpProxy &&
disableKcpInput == other.disableKcpInput &&
disableRelayKcp == other.disableRelayKcp &&
proxyForwardBySystem == other.proxyForwardBySystem;
}
class KVNetworkStatus {
final BigInt totalNodes;
final List<KVNodeInfo> nodes;
+146 -4
View File
@@ -85,7 +85,8 @@ abstract class RustLibApi extends BaseApi {
required String specifiedIp,
required String roomName,
required String roomPassword,
required List<String> severurl});
required List<String> severurl,
required FlagsC flag});
Future<String> crateApiSimpleEasytierVersion();
@@ -174,7 +175,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
required String specifiedIp,
required String roomName,
required String roomPassword,
required List<String> severurl}) {
required List<String> severurl,
required FlagsC flag}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
@@ -184,6 +186,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_String(roomName, serializer);
sse_encode_String(roomPassword, serializer);
sse_encode_list_String(severurl, serializer);
sse_encode_box_autoadd_flags_c(flag, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer,
funcId: 2, port: port_);
},
@@ -198,7 +201,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
specifiedIp,
roomName,
roomPassword,
severurl
severurl,
flag
],
apiImpl: this,
));
@@ -212,7 +216,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
"specifiedIp",
"roomName",
"roomPassword",
"severurl"
"severurl",
"flag"
],
);
@@ -515,6 +520,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as bool;
}
@protected
FlagsC dco_decode_box_autoadd_flags_c(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return dco_decode_flags_c(raw);
}
@protected
double dco_decode_f_32(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -527,6 +538,36 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as double;
}
@protected
FlagsC dco_decode_flags_c(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
final arr = raw as List<dynamic>;
if (arr.length != 20)
throw Exception('unexpected arr length: expect 20 but see ${arr.length}');
return FlagsC(
defaultProtocol: dco_decode_String(arr[0]),
devName: dco_decode_String(arr[1]),
enableEncryption: dco_decode_bool(arr[2]),
enableIpv6: dco_decode_bool(arr[3]),
mtu: dco_decode_u_32(arr[4]),
latencyFirst: dco_decode_bool(arr[5]),
enableExitNode: dco_decode_bool(arr[6]),
noTun: dco_decode_bool(arr[7]),
useSmoltcp: dco_decode_bool(arr[8]),
relayNetworkWhitelist: dco_decode_String(arr[9]),
disableP2P: dco_decode_bool(arr[10]),
relayAllPeerRpc: dco_decode_bool(arr[11]),
disableUdpHolePunching: dco_decode_bool(arr[12]),
multiThread: dco_decode_bool(arr[13]),
dataCompressAlgo: dco_decode_i_32(arr[14]),
bindDevice: dco_decode_bool(arr[15]),
enableKcpProxy: dco_decode_bool(arr[16]),
disableKcpInput: dco_decode_bool(arr[17]),
disableRelayKcp: dco_decode_bool(arr[18]),
proxyForwardBySystem: dco_decode_bool(arr[19]),
);
}
@protected
int dco_decode_i_32(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -657,6 +698,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
}
@protected
int dco_decode_u_32(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return raw as int;
}
@protected
BigInt dco_decode_u_64(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -766,6 +813,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getUint8() != 0;
}
@protected
FlagsC sse_decode_box_autoadd_flags_c(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
return (sse_decode_flags_c(deserializer));
}
@protected
double sse_decode_f_32(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -778,6 +831,52 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getFloat64();
}
@protected
FlagsC sse_decode_flags_c(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
var var_defaultProtocol = sse_decode_String(deserializer);
var var_devName = sse_decode_String(deserializer);
var var_enableEncryption = sse_decode_bool(deserializer);
var var_enableIpv6 = sse_decode_bool(deserializer);
var var_mtu = sse_decode_u_32(deserializer);
var var_latencyFirst = sse_decode_bool(deserializer);
var var_enableExitNode = sse_decode_bool(deserializer);
var var_noTun = sse_decode_bool(deserializer);
var var_useSmoltcp = sse_decode_bool(deserializer);
var var_relayNetworkWhitelist = sse_decode_String(deserializer);
var var_disableP2P = sse_decode_bool(deserializer);
var var_relayAllPeerRpc = sse_decode_bool(deserializer);
var var_disableUdpHolePunching = sse_decode_bool(deserializer);
var var_multiThread = sse_decode_bool(deserializer);
var var_dataCompressAlgo = sse_decode_i_32(deserializer);
var var_bindDevice = sse_decode_bool(deserializer);
var var_enableKcpProxy = sse_decode_bool(deserializer);
var var_disableKcpInput = sse_decode_bool(deserializer);
var var_disableRelayKcp = sse_decode_bool(deserializer);
var var_proxyForwardBySystem = sse_decode_bool(deserializer);
return FlagsC(
defaultProtocol: var_defaultProtocol,
devName: var_devName,
enableEncryption: var_enableEncryption,
enableIpv6: var_enableIpv6,
mtu: var_mtu,
latencyFirst: var_latencyFirst,
enableExitNode: var_enableExitNode,
noTun: var_noTun,
useSmoltcp: var_useSmoltcp,
relayNetworkWhitelist: var_relayNetworkWhitelist,
disableP2P: var_disableP2P,
relayAllPeerRpc: var_relayAllPeerRpc,
disableUdpHolePunching: var_disableUdpHolePunching,
multiThread: var_multiThread,
dataCompressAlgo: var_dataCompressAlgo,
bindDevice: var_bindDevice,
enableKcpProxy: var_enableKcpProxy,
disableKcpInput: var_disableKcpInput,
disableRelayKcp: var_disableRelayKcp,
proxyForwardBySystem: var_proxyForwardBySystem);
}
@protected
int sse_decode_i_32(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -940,6 +1039,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return (var_field0, var_field1);
}
@protected
int sse_decode_u_32(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
return deserializer.buffer.getUint32();
}
@protected
BigInt sse_decode_u_64(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -1049,6 +1154,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
serializer.buffer.putUint8(self ? 1 : 0);
}
@protected
void sse_encode_box_autoadd_flags_c(FlagsC self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_flags_c(self, serializer);
}
@protected
void sse_encode_f_32(double self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -1061,6 +1172,31 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
serializer.buffer.putFloat64(self);
}
@protected
void sse_encode_flags_c(FlagsC self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_String(self.defaultProtocol, serializer);
sse_encode_String(self.devName, serializer);
sse_encode_bool(self.enableEncryption, serializer);
sse_encode_bool(self.enableIpv6, serializer);
sse_encode_u_32(self.mtu, serializer);
sse_encode_bool(self.latencyFirst, serializer);
sse_encode_bool(self.enableExitNode, serializer);
sse_encode_bool(self.noTun, serializer);
sse_encode_bool(self.useSmoltcp, serializer);
sse_encode_String(self.relayNetworkWhitelist, serializer);
sse_encode_bool(self.disableP2P, serializer);
sse_encode_bool(self.relayAllPeerRpc, serializer);
sse_encode_bool(self.disableUdpHolePunching, serializer);
sse_encode_bool(self.multiThread, serializer);
sse_encode_i_32(self.dataCompressAlgo, serializer);
sse_encode_bool(self.bindDevice, serializer);
sse_encode_bool(self.enableKcpProxy, serializer);
sse_encode_bool(self.disableKcpInput, serializer);
sse_encode_bool(self.disableRelayKcp, serializer);
sse_encode_bool(self.proxyForwardBySystem, serializer);
}
@protected
void sse_encode_i_32(int self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -1183,6 +1319,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
self.$2, serializer);
}
@protected
void sse_encode_u_32(int self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
serializer.buffer.putUint32(self);
}
@protected
void sse_encode_u_64(BigInt self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
+27
View File
@@ -77,12 +77,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool dco_decode_bool(dynamic raw);
@protected
FlagsC dco_decode_box_autoadd_flags_c(dynamic raw);
@protected
double dco_decode_f_32(dynamic raw);
@protected
double dco_decode_f_64(dynamic raw);
@protected
FlagsC dco_decode_flags_c(dynamic raw);
@protected
int dco_decode_i_32(dynamic raw);
@@ -130,6 +136,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
) dco_decode_record_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_peer_info_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_route(
dynamic raw);
@protected
int dco_decode_u_32(dynamic raw);
@protected
BigInt dco_decode_u_64(dynamic raw);
@@ -188,12 +197,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
FlagsC sse_decode_box_autoadd_flags_c(SseDeserializer deserializer);
@protected
double sse_decode_f_32(SseDeserializer deserializer);
@protected
double sse_decode_f_64(SseDeserializer deserializer);
@protected
FlagsC sse_decode_flags_c(SseDeserializer deserializer);
@protected
int sse_decode_i_32(SseDeserializer deserializer);
@@ -242,6 +257,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
) sse_decode_record_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_peer_info_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_route(
SseDeserializer deserializer);
@protected
int sse_decode_u_32(SseDeserializer deserializer);
@protected
BigInt sse_decode_u_64(SseDeserializer deserializer);
@@ -300,12 +318,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_flags_c(FlagsC self, SseSerializer serializer);
@protected
void sse_encode_f_32(double self, SseSerializer serializer);
@protected
void sse_encode_f_64(double self, SseSerializer serializer);
@protected
void sse_encode_flags_c(FlagsC self, SseSerializer serializer);
@protected
void sse_encode_i_32(int self, SseSerializer serializer);
@@ -355,6 +379,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
sse_encode_record_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_peer_info_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_route(
(List<PeerInfo>, List<Route>) self, SseSerializer serializer);
@protected
void sse_encode_u_32(int self, SseSerializer serializer);
@protected
void sse_encode_u_64(BigInt self, SseSerializer serializer);
+27
View File
@@ -79,12 +79,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool dco_decode_bool(dynamic raw);
@protected
FlagsC dco_decode_box_autoadd_flags_c(dynamic raw);
@protected
double dco_decode_f_32(dynamic raw);
@protected
double dco_decode_f_64(dynamic raw);
@protected
FlagsC dco_decode_flags_c(dynamic raw);
@protected
int dco_decode_i_32(dynamic raw);
@@ -132,6 +138,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
) dco_decode_record_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_peer_info_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_route(
dynamic raw);
@protected
int dco_decode_u_32(dynamic raw);
@protected
BigInt dco_decode_u_64(dynamic raw);
@@ -190,12 +199,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
FlagsC sse_decode_box_autoadd_flags_c(SseDeserializer deserializer);
@protected
double sse_decode_f_32(SseDeserializer deserializer);
@protected
double sse_decode_f_64(SseDeserializer deserializer);
@protected
FlagsC sse_decode_flags_c(SseDeserializer deserializer);
@protected
int sse_decode_i_32(SseDeserializer deserializer);
@@ -244,6 +259,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
) sse_decode_record_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_peer_info_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_route(
SseDeserializer deserializer);
@protected
int sse_decode_u_32(SseDeserializer deserializer);
@protected
BigInt sse_decode_u_64(SseDeserializer deserializer);
@@ -302,12 +320,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_flags_c(FlagsC self, SseSerializer serializer);
@protected
void sse_encode_f_32(double self, SseSerializer serializer);
@protected
void sse_encode_f_64(double self, SseSerializer serializer);
@protected
void sse_encode_flags_c(FlagsC self, SseSerializer serializer);
@protected
void sse_encode_i_32(int self, SseSerializer serializer);
@@ -357,6 +381,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
sse_encode_record_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_peer_info_list_auto_owned_rust_opaque_flutter_rust_bridgefor_generated_rust_auto_opaque_inner_route(
(List<PeerInfo>, List<Route>) self, SseSerializer serializer);
@protected
void sse_encode_u_32(int self, SseSerializer serializer);
@protected
void sse_encode_u_64(BigInt self, SseSerializer serializer);
+401 -69
View File
@@ -1,104 +1,436 @@
import 'package:astral/src/rust/api/simple.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../config/app_config.dart';
class KM extends ChangeNotifier {
final _config = AppConfig();
int _count = 0;
int get count => _count;
// 全局配置实例
final appConfigProvider = Provider<AppConfig>((ref) => AppConfig());
void increment() {
_count++;
notifyListeners(); // 通知监听器重建UI
}
// 计数器相关
class CountNotifier extends StateNotifier<int> {
CountNotifier() : super(0);
// 房间名
String get roomName => _config.roomName;
set roomName(String value) {
void increment() => state++;
}
final countProvider =
StateNotifierProvider<CountNotifier, int>((ref) => CountNotifier());
// 房间名相关
class RoomNameNotifier extends StateNotifier<String> {
final AppConfig _config;
RoomNameNotifier(this._config) : super(_config.roomName);
void setRoomName(String value) {
_config.setRoomName(value);
notifyListeners(); // 通知监听器重建UI
state = value;
}
}
//房间密码设置
String get roomPassword => _config.roomPassword;
set roomPassword(String value) {
final roomNameProvider = StateNotifierProvider<RoomNameNotifier, String>((ref) {
return RoomNameNotifier(ref.watch(appConfigProvider));
});
// 房间密码相关
class RoomPasswordNotifier extends StateNotifier<String> {
final AppConfig _config;
RoomPasswordNotifier(this._config) : super(_config.roomPassword);
void setRoomPassword(String value) {
_config.setRoomPassword(value);
notifyListeners();
state = value;
}
}
//用户名设置
String get username => _config.username;
set username(String value) {
final roomPasswordProvider =
StateNotifierProvider<RoomPasswordNotifier, String>((ref) {
return RoomPasswordNotifier(ref.watch(appConfigProvider));
});
// 用户名相关
class UsernameNotifier extends StateNotifier<String> {
final AppConfig _config;
UsernameNotifier(this._config) : super(_config.username);
void setUsername(String value) {
_config.setUsername(value);
notifyListeners();
state = value;
}
}
//虚拟IP设置
String get virtualIP => _config.virtualIP;
set virtualIP(String value) {
final usernameProvider = StateNotifierProvider<UsernameNotifier, String>((ref) {
return UsernameNotifier(ref.watch(appConfigProvider));
});
// 虚拟IP相关
class VirtualIPNotifier extends StateNotifier<String> {
final AppConfig _config;
VirtualIPNotifier(this._config) : super(_config.virtualIP);
void setVirtualIP(String value) {
_config.setVirtualIP(value);
notifyListeners();
state = value;
}
}
//动态获取IP设置
bool get dynamicIP => _config.dynamicIP;
set dynamicIP(bool value) {
final virtualIPProvider =
StateNotifierProvider<VirtualIPNotifier, String>((ref) {
return VirtualIPNotifier(ref.watch(appConfigProvider));
});
// 动态获取IP设置相关
class DynamicIPNotifier extends StateNotifier<bool> {
final AppConfig _config;
DynamicIPNotifier(this._config) : super(_config.dynamicIP);
void setDynamicIP(bool value) {
_config.setDynamicIP(value);
notifyListeners();
state = value;
}
}
//服务器列表
List<Map<String, dynamic>> get serverList => _config.serverList;
set serverList(List<Map<String, dynamic>> value) {
final dynamicIPProvider = StateNotifierProvider<DynamicIPNotifier, bool>((ref) {
return DynamicIPNotifier(ref.watch(appConfigProvider));
});
// 服务器列表相关
class ServerListNotifier extends StateNotifier<List<Map<String, dynamic>>> {
final AppConfig _config;
ServerListNotifier(this._config) : super(_config.serverList);
void setServerList(List<Map<String, dynamic>> value) {
List<Map<String, dynamic>> convertedList = value.map((item) {
return Map<String, dynamic>.from(item);
}).toList();
_config.setServerList(convertedList);
notifyListeners();
state = convertedList;
}
//获取选中的服务器
//获取选中的服务器
List<String> get serverIP {
try {
final selected =
serverList.where((server) => server['selected'] == true).toList();
if (selected.isEmpty && serverList.isNotEmpty) {
final firstServer = serverList.first;
if (firstServer['url'] is String) {
return [firstServer['url'] as String];
}
return [];
}
return selected
.where((server) => server['url'] is String)
.map((server) => server['url'] as String)
.toList();
} catch (e) {
debugPrint('获取服务器IP时出错: $e');
return [];
}
}
//设置服务器选中状态
void setServerSelected(String url, bool selected) {
final servers = serverList;
final servers = [...state];
for (var i = 0; i < servers.length; i++) {
if (servers[i]['url'] == url) {
servers[i]['selected'] = selected;
}
}
serverList = servers;
}
// 节点列表
List<KVNodeInfo> _nodes = [];
List<KVNodeInfo> get nodes => _nodes;
set nodes(List<KVNodeInfo> value) {
_nodes = value;
notifyListeners();
setServerList(servers);
}
}
final serverListProvider =
StateNotifierProvider<ServerListNotifier, List<Map<String, dynamic>>>(
(ref) {
return ServerListNotifier(ref.watch(appConfigProvider));
});
// 选中的服务器IP
final serverIPProvider = Provider<List<String>>((ref) {
final serverList = ref.watch(serverListProvider);
try {
final selected =
serverList.where((server) => server['selected'] == true).toList();
if (selected.isEmpty && serverList.isNotEmpty) {
final firstServer = serverList.first;
if (firstServer['url'] is String) {
return [firstServer['url'] as String];
}
return [];
}
return selected
.where((server) => server['url'] is String)
.map((server) => server['url'] as String)
.toList();
} catch (e) {
debugPrint('获取服务器IP时出错: $e');
return [];
}
});
//返回选中的服务器
final selectedServerProvider = Provider<List<ServerConfig>>((ref) {
final serverList = ref.watch(serverListProvider);
final selected =
serverList.where((server) => server['selected'] == true).toList();
if (selected.isEmpty) {
return [];
}
// 将选中的服务器转换为ServerConfig对象列表
return selected
.map((server) => ServerConfig(
url: server['url'] ?? '',
name: server['name'] ?? '',
selected: true,
tcp: server['tcp'] ?? true,
udp: server['udp'] ?? true,
ws: server['ws'] ?? false,
wss: server['wss'] ?? false,
quic: server['quic'] ?? false,
))
.toList();
});
// 节点列表相关
class NodesNotifier extends StateNotifier<List<KVNodeInfo>> {
NodesNotifier() : super([]);
void setNodes(List<KVNodeInfo> value) {
state = value;
}
}
final nodesProvider = StateNotifierProvider<NodesNotifier, List<KVNodeInfo>>(
(ref) => NodesNotifier());
// 高级配置相关
class AdvancedConfigNotifier extends StateNotifier<Map<String, dynamic>> {
final AppConfig _config;
AdvancedConfigNotifier(this._config)
: super({
'defaultProtocol': _config.advanced.defaultProtocol,
'devName': _config.advanced.devName,
'enableEncryption': _config.advanced.enableEncryption,
'enableIpv6': _config.advanced.enableIpv6,
'mtu': _config.advanced.mtu,
'latencyFirst': _config.advanced.latencyFirst,
'enableExitNode': _config.advanced.enableExitNode,
'proxyForwardBySystem': _config.advanced.proxyForwardBySystem,
'noTun': _config.advanced.noTun,
'useSmoltcp': _config.advanced.useSmoltcp,
'relayNetworkWhitelist': _config.advanced.relayNetworkWhitelist,
'disableP2p': _config.advanced.disableP2p,
'relayAllPeerRpc': _config.advanced.relayAllPeerRpc,
'disableUdpHolePunching': _config.advanced.disableUdpHolePunching,
'multiThread': _config.advanced.multiThread,
'dataCompressAlgo': _config.advanced.dataCompressAlgo,
'bindDevice': _config.advanced.bindDevice,
'enableKcpProxy': _config.advanced.enableKcpProxy,
'disableKcpInput': _config.advanced.disableKcpInput,
'disableRelayKcp': _config.advanced.disableRelayKcp,
});
// 更新单个配置项
Future<void> updateConfig(String key, dynamic value) async {
if (state.containsKey(key) && state[key] != value) {
final newState = {...state, key: value};
state = newState;
// 使用通用方法更新配置
await _config.updateAdvancedConfig(
defaultProtocol: key == 'defaultProtocol' ? value : null,
devName: key == 'devName' ? value : null,
enableEncryption: key == 'enableEncryption' ? value : null,
enableIpv6: key == 'enableIpv6' ? value : null,
mtu: key == 'mtu' ? value : null,
latencyFirst: key == 'latencyFirst' ? value : null,
enableExitNode: key == 'enableExitNode' ? value : null,
proxyForwardBySystem: key == 'proxyForwardBySystem' ? value : null,
noTun: key == 'noTun' ? value : null,
useSmoltcp: key == 'useSmoltcp' ? value : null,
relayNetworkWhitelist: key == 'relayNetworkWhitelist' ? value : null,
disableP2p: key == 'disableP2p' ? value : null,
relayAllPeerRpc: key == 'relayAllPeerRpc' ? value : null,
disableUdpHolePunching: key == 'disableUdpHolePunching' ? value : null,
multiThread: key == 'multiThread' ? value : null,
dataCompressAlgo: key == 'dataCompressAlgo' ? value : null,
bindDevice: key == 'bindDevice' ? value : null,
enableKcpProxy: key == 'enableKcpProxy' ? value : null,
disableKcpInput: key == 'disableKcpInput' ? value : null,
disableRelayKcp: key == 'disableRelayKcp' ? value : null,
);
}
}
// 批量更新配置
Future<void> updateMultipleConfigs(Map<String, dynamic> updates) async {
final newState = {...state, ...updates};
state = newState;
// 使用通用方法更新配置
await _config.updateAdvancedConfig(
defaultProtocol: updates.containsKey('defaultProtocol')
? updates['defaultProtocol']
: null,
devName: updates.containsKey('devName') ? updates['devName'] : null,
enableEncryption: updates.containsKey('enableEncryption')
? updates['enableEncryption']
: null,
enableIpv6:
updates.containsKey('enableIpv6') ? updates['enableIpv6'] : null,
mtu: updates.containsKey('mtu') ? updates['mtu'] : null,
latencyFirst:
updates.containsKey('latencyFirst') ? updates['latencyFirst'] : null,
enableExitNode: updates.containsKey('enableExitNode')
? updates['enableExitNode']
: null,
proxyForwardBySystem: updates.containsKey('proxyForwardBySystem')
? updates['proxyForwardBySystem']
: null,
noTun: updates.containsKey('noTun') ? updates['noTun'] : null,
useSmoltcp:
updates.containsKey('useSmoltcp') ? updates['useSmoltcp'] : null,
relayNetworkWhitelist: updates.containsKey('relayNetworkWhitelist')
? updates['relayNetworkWhitelist']
: null,
disableP2p:
updates.containsKey('disableP2p') ? updates['disableP2p'] : null,
relayAllPeerRpc: updates.containsKey('relayAllPeerRpc')
? updates['relayAllPeerRpc']
: null,
disableUdpHolePunching: updates.containsKey('disableUdpHolePunching')
? updates['disableUdpHolePunching']
: null,
multiThread:
updates.containsKey('multiThread') ? updates['multiThread'] : null,
dataCompressAlgo: updates.containsKey('dataCompressAlgo')
? updates['dataCompressAlgo']
: null,
bindDevice:
updates.containsKey('bindDevice') ? updates['bindDevice'] : null,
enableKcpProxy: updates.containsKey('enableKcpProxy')
? updates['enableKcpProxy']
: null,
disableKcpInput: updates.containsKey('disableKcpInput')
? updates['disableKcpInput']
: null,
disableRelayKcp: updates.containsKey('disableRelayKcp')
? updates['disableRelayKcp']
: null,
);
}
// 为每个配置项提供单独的更新方法
Future<void> setDefaultProtocol(String value) async =>
updateConfig('defaultProtocol', value);
Future<void> setDevName(String value) async => updateConfig('devName', value);
Future<void> setEnableEncryption(bool value) async =>
updateConfig('enableEncryption', value);
Future<void> setEnableIpv6(bool value) async =>
updateConfig('enableIpv6', value);
Future<void> setMtu(int value) async => updateConfig('mtu', value);
Future<void> setLatencyFirst(bool value) async =>
updateConfig('latencyFirst', value);
Future<void> setEnableExitNode(bool value) async =>
updateConfig('enableExitNode', value);
Future<void> setProxyForwardBySystem(bool value) async =>
updateConfig('proxyForwardBySystem', value);
Future<void> setNoTun(bool value) async => updateConfig('noTun', value);
Future<void> setUseSmoltcp(bool value) async =>
updateConfig('useSmoltcp', value);
Future<void> setRelayNetworkWhitelist(String value) async =>
updateConfig('relayNetworkWhitelist', value);
Future<void> setDisableP2p(bool value) async =>
updateConfig('disableP2p', value);
Future<void> setRelayAllPeerRpc(bool value) async =>
updateConfig('relayAllPeerRpc', value);
Future<void> setDisableUdpHolePunching(bool value) async =>
updateConfig('disableUdpHolePunching', value);
Future<void> setMultiThread(bool value) async =>
updateConfig('multiThread', value);
Future<void> setDataCompressAlgo(String value) async =>
updateConfig('dataCompressAlgo', value);
Future<void> setBindDevice(bool value) async =>
updateConfig('bindDevice', value);
Future<void> setEnableKcpProxy(bool value) async =>
updateConfig('enableKcpProxy', value);
Future<void> setDisableKcpInput(bool value) async =>
updateConfig('disableKcpInput', value);
Future<void> setDisableRelayKcp(bool value) async =>
updateConfig('disableRelayKcp', value);
}
final advancedConfigProvider =
StateNotifierProvider<AdvancedConfigNotifier, Map<String, dynamic>>((ref) {
return AdvancedConfigNotifier(ref.watch(appConfigProvider));
});
// 为每个高级配置项创建单独的Provider,方便在UI中使用
final defaultProtocolProvider = Provider<String>((ref) {
return ref.watch(advancedConfigProvider)['defaultProtocol'];
});
final devNameProvider = Provider<String>((ref) {
return ref.watch(advancedConfigProvider)['devName'];
});
final enableEncryptionProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['enableEncryption'];
});
final enableIpv6Provider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['enableIpv6'];
});
final mtuProvider = Provider<int>((ref) {
return ref.watch(advancedConfigProvider)['mtu'];
});
final latencyFirstProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['latencyFirst'];
});
final enableExitNodeProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['enableExitNode'];
});
final proxyForwardBySystemProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['proxyForwardBySystem'];
});
final noTunProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['noTun'];
});
final useSmoltcpProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['useSmoltcp'];
});
final relayNetworkWhitelistProvider = Provider<String>((ref) {
return ref.watch(advancedConfigProvider)['relayNetworkWhitelist'];
});
final disableP2pProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['disableP2p'];
});
final relayAllPeerRpcProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['relayAllPeerRpc'];
});
final disableUdpHolePunchingProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['disableUdpHolePunching'];
});
final multiThreadProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['multiThread'];
});
final dataCompressAlgoProvider = Provider<String>((ref) {
return ref.watch(advancedConfigProvider)['dataCompressAlgo'];
});
final bindDeviceProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['bindDevice'];
});
final enableKcpProxyProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['enableKcpProxy'];
});
final disableKcpInputProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['disableKcpInput'];
});
final disableRelayKcpProvider = Provider<bool>((ref) {
return ref.watch(advancedConfigProvider)['disableRelayKcp'];
});
+198
View File
@@ -0,0 +1,198 @@
import 'dart:convert';
// 主入口类
class StatusPageData {
final Config config;
final Incident incident;
final List<PublicGroup> publicGroupList;
StatusPageData({
required this.config,
required this.incident,
required this.publicGroupList,
});
factory StatusPageData.fromJson(Map<String, dynamic> json) => StatusPageData(
config: Config.fromJson(json['config']),
incident: Incident.fromJson(json['incident']),
publicGroupList: List<PublicGroup>.from(
json['publicGroupList'].map((x) => PublicGroup.fromJson(x))),
);
}
// 配置信息
class Config {
final String slug;
final String title;
final String description;
final String icon;
final String theme;
final bool published;
final bool showTags;
final String customCSS;
final String footerText;
final bool showPoweredBy;
final dynamic googleAnalyticsId;
final bool showCertificateExpiry;
Config({
required this.slug,
required this.title,
required this.description,
required this.icon,
required this.theme,
required this.published,
required this.showTags,
required this.customCSS,
required this.footerText,
required this.showPoweredBy,
this.googleAnalyticsId,
required this.showCertificateExpiry,
});
factory Config.fromJson(Map<String, dynamic> json) => Config(
slug: json['slug'],
title: json['title'],
description: json['description'],
icon: json['icon'],
theme: json['theme'],
published: json['published'],
showTags: json['showTags'],
customCSS: json['customCSS'],
footerText: json['footerText'],
showPoweredBy: json['showPoweredBy'],
googleAnalyticsId: json['googleAnalyticsId'],
showCertificateExpiry: json['showCertificateExpiry'],
);
}
// 事件信息
class Incident {
final int id;
final String style;
final String title;
final String content;
final int pin;
final DateTime createdDate;
final DateTime lastUpdatedDate;
Incident({
required this.id,
required this.style,
required this.title,
required this.content,
required this.pin,
required this.createdDate,
required this.lastUpdatedDate,
});
factory Incident.fromJson(Map<String, dynamic> json) => Incident(
id: json['id'],
style: json['style'],
title: json['title'],
content: json['content'],
pin: json['pin'],
createdDate: DateTime.parse(json['createdDate']),
lastUpdatedDate: DateTime.parse(json['lastUpdatedDate']),
);
}
// 公共服务器组
class PublicGroup {
final int id;
final String name;
final int weight;
final List<Monitor> monitorList;
PublicGroup({
required this.id,
required this.name,
required this.weight,
required this.monitorList,
});
factory PublicGroup.fromJson(Map<String, dynamic> json) => PublicGroup(
id: json['id'],
name: json['name'],
weight: json['weight'],
monitorList: List<Monitor>.from(
json['monitorList'].map((x) => Monitor.fromJson(x))),
);
}
// 监控项
class Monitor {
final int id;
final String name;
final int sendUrl;
final String type;
final List<Tag> tags;
final int? certExpiryDaysRemaining;
final bool? validCert;
Monitor({
required this.id,
required this.name,
required this.sendUrl,
required this.type,
required this.tags,
this.certExpiryDaysRemaining,
this.validCert,
});
factory Monitor.fromJson(Map<String, dynamic> json) => Monitor(
id: json['id'],
name: json['name'],
sendUrl: json['sendUrl'],
type: json['type'],
tags: List<Tag>.from(json['tags'].map((x) => Tag.fromJson(x))),
certExpiryDaysRemaining: json['certExpiryDaysRemaining'],
validCert: json['validCert'],
);
}
// 标签
class Tag {
final int id;
final int monitorId;
final int tagId;
final String value;
final String name;
final String color;
Tag({
required this.id,
required this.monitorId,
required this.tagId,
required this.value,
required this.name,
required this.color,
});
factory Tag.fromJson(Map<String, dynamic> json) => Tag(
id: json['id'],
monitorId: json['monitor_id'],
tagId: json['tag_id'],
value: json['value'],
name: json['name'],
color: json['color'],
);
}
// // 使用示例
// void main() {
// final jsonString = '''{/* 你的原始JSON数据 */}''';
// final data = StatusPageData.fromJson(jsonDecode(jsonString));
// // 示例:获取第一个服务器组的名称
// print('第一组名称: ${data.publicGroupList.first.name}');
// // 示例:列出所有可中转的服务器
// final transferableServers = data.publicGroupList
// .expand((group) => group.monitorList)
// .where((monitor) => monitor.tags.any((tag) => tag.name == '可中转'))
// .toList();
// print('可中转服务器数量: ${transferableServers.length}');
// }