Skip to content

Commit dcc7e5b

Browse files
committed
增加流量统计、支持ws
1 parent 194f298 commit dcc7e5b

25 files changed

+1827
-278
lines changed

android/app/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ android {
4545
ndk {
4646
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
4747
}
48-
versionName "1.2.10"
48+
versionName "1.2.11"
4949
}
5050

5151
buildTypes {
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

lib/about_page.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class AboutPage extends StatelessWidget {
4747
),
4848
const SizedBox(height: 20),
4949
const Text(
50-
'版本号: 1.2.10-测试版',
50+
'版本号: 1.2.11-预发布版',
5151
style: TextStyle(fontSize: 16),
5252
textAlign: TextAlign.center,
5353
),

lib/connected_page.dart

+53-23
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'dart:async';
2+
import 'dart:io';
3+
14
import 'package:flutter/material.dart';
25
import 'connect_log.dart';
36
import 'network_config.dart';
@@ -6,6 +9,7 @@ import 'src/rust/api/vnt_api.dart';
69
import 'package:json2yaml/json2yaml.dart';
710

811
import 'vnt/vnt_manager.dart';
12+
import 'widgets/dual_bar_chart.dart';
913

1014
class ConnectDetailPage extends StatefulWidget {
1115
final NetworkConfig config;
@@ -19,34 +23,50 @@ class ConnectDetailPage extends StatefulWidget {
1923
}
2024

2125
class _ConnectDetailPageState extends State<ConnectDetailPage> {
26+
final GlobalKey<StatisticsChartState> _keyChart =
27+
GlobalKey<StatisticsChartState>();
28+
2229
int _selectedIndex = 0;
2330
List<Map<String, String>> deviceList = [];
2431
List<Map<String, String>> routeList = [];
25-
32+
Timer? _timer;
2633
@override
2734
void initState() {
2835
super.initState();
29-
_loadData();
36+
_loadData(false);
37+
_timer = Timer.periodic(const Duration(seconds: 5), (Timer timer) {
38+
_loadData(true);
39+
});
40+
}
41+
42+
@override
43+
void dispose() {
44+
_timer?.cancel(); // 取消定时器以防止内存泄漏
45+
super.dispose();
3046
}
3147

3248
void _onItemTapped(int index) {
3349
setState(() {
3450
_selectedIndex = index;
35-
_loadData();
51+
_loadData(false);
3652
});
3753
}
3854

39-
Future<void> _loadData() async {
55+
Future<void> _loadData(bool timer) async {
4056
if (_selectedIndex == 0) {
41-
deviceList = _fetchDeviceList();
4257
setState(() {
43-
deviceList = deviceList;
58+
deviceList = _fetchDeviceList();
4459
});
45-
} else {
46-
routeList = _fetchRouteList();
60+
} else if (_selectedIndex == 1) {
4761
setState(() {
48-
routeList = routeList;
62+
routeList = _fetchRouteList();
4963
});
64+
} else {
65+
if (timer) {
66+
_keyChart.currentState?.updateData();
67+
} else {
68+
_keyChart.currentState?.updateBarChart();
69+
}
5070
}
5171
}
5272

@@ -93,20 +113,21 @@ class _ConnectDetailPageState extends State<ConnectDetailPage> {
93113
title: const Text('组网', style: TextStyle(color: Colors.white)),
94114
backgroundColor: Colors.teal,
95115
actions: [
96-
Padding(
97-
padding: const EdgeInsets.symmetric(horizontal: 8.0),
98-
child: IconButton(
99-
icon: const Text('日志', style: TextStyle(color: Colors.white)),
100-
onPressed: () {
101-
Navigator.push(
102-
context,
103-
MaterialPageRoute(
104-
builder: (context) => LogPage(),
105-
),
106-
);
107-
},
116+
if (!Platform.isAndroid)
117+
Padding(
118+
padding: const EdgeInsets.symmetric(horizontal: 8.0),
119+
child: IconButton(
120+
icon: const Text('日志', style: TextStyle(color: Colors.white)),
121+
onPressed: () {
122+
Navigator.push(
123+
context,
124+
MaterialPageRoute(
125+
builder: (context) => LogPage(),
126+
),
127+
);
128+
},
129+
),
108130
),
109-
),
110131
Padding(
111132
padding: const EdgeInsets.symmetric(horizontal: 8.0),
112133
child: IconButton(
@@ -173,6 +194,10 @@ class _ConnectDetailPageState extends State<ConnectDetailPage> {
173194
icon: Icon(Icons.router),
174195
label: '路由',
175196
),
197+
BottomNavigationBarItem(
198+
icon: Icon(Icons.signal_cellular_alt),
199+
label: '统计',
200+
),
176201
],
177202
currentIndex: _selectedIndex,
178203
selectedItemColor: Colors.amber[800],
@@ -182,12 +207,17 @@ class _ConnectDetailPageState extends State<ConnectDetailPage> {
182207
}
183208

184209
List<Widget> _buildWidgetOptions() {
210+
// var chartAList = _chartAList();
185211
return [
186212
DeviceList(
187213
deviceList: deviceList,
188214
vntBox: widget.vntBox,
189215
),
190216
RouteList(routeList: routeList),
217+
StatisticsChart(
218+
key: _keyChart,
219+
vntBox: widget.vntBox,
220+
)
191221
];
192222
}
193223

@@ -306,7 +336,7 @@ class DeviceList extends StatelessWidget {
306336
}
307337
if (routeList != null) {
308338
var route = routeList.map((v) {
309-
return '${v.isTcp ? "TCP" : "UDP"}-${v.metric <= 1 ? "P2P" : "Relay"}-${v.addr} rt=${v.rt}';
339+
return '$v-${v.metric <= 1 ? "P2P" : "Relay"}-${v.addr} rt=${v.rt}';
310340
}).toList();
311341
map.addAll({
312342
'route': route,

lib/main.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,9 @@ class _HomePageState extends State<HomePage> with WindowListener {
506506
actions: [
507507
TextButton(
508508
onPressed: () async {
509+
Navigator.of(context).pop();
509510
await vntManager.removeAll();
510511
loadConnectState();
511-
Navigator.of(context).pop();
512512
},
513513
style: TextButton.styleFrom(
514514
foregroundColor: Colors.white,

lib/network_config.dart

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class NetworkConfig {
1111
List<String> portMappings;
1212
String groupPassword;
1313
bool isServerEncrypted;
14-
bool isTcp;
14+
String protocol;
1515
bool dataFingerprintVerification;
1616
String encryptionAlgorithm;
1717
String deviceID;
@@ -40,7 +40,7 @@ class NetworkConfig {
4040
required this.portMappings,
4141
required this.groupPassword,
4242
required this.isServerEncrypted,
43-
required this.isTcp,
43+
required this.protocol,
4444
required this.dataFingerprintVerification,
4545
required this.encryptionAlgorithm,
4646
required this.deviceID,
@@ -70,7 +70,7 @@ class NetworkConfig {
7070
'mapping': portMappings,
7171
'password': groupPassword,
7272
'server_encrypt': isServerEncrypted,
73-
'tcp': isTcp,
73+
'tcp': protocol,
7474
'finger': dataFingerprintVerification,
7575
'cipher_model': encryptionAlgorithm,
7676
'device_id': deviceID,
@@ -101,7 +101,7 @@ class NetworkConfig {
101101
if (portMappings.isNotEmpty) 'mapping': portMappings,
102102
if (groupPassword.isNotEmpty) 'password': groupPassword,
103103
if (isServerEncrypted) 'server_encrypt': isServerEncrypted,
104-
if (isTcp) 'tcp': isTcp,
104+
if (protocol.isNotEmpty) 'protocol': protocol,
105105
if (dataFingerprintVerification) 'finger': dataFingerprintVerification,
106106
if (encryptionAlgorithm.isNotEmpty) 'cipher_model': encryptionAlgorithm,
107107
if (deviceID.isNotEmpty) 'device_id': deviceID,
@@ -134,7 +134,7 @@ class NetworkConfig {
134134
portMappings: List<String>.from(json['mapping']),
135135
groupPassword: json['password'],
136136
isServerEncrypted: json['server_encrypt'],
137-
isTcp: json['tcp'],
137+
protocol: json['protocol']??'UDP',
138138
dataFingerprintVerification: json['finger'],
139139
encryptionAlgorithm: json['cipher_model'],
140140
deviceID: json['device_id'],

lib/network_config_input_page.dart

+12-5
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class _NetworkConfigInputPageState extends State<NetworkConfigInputPage> {
115115
}
116116
_groupPasswordController.text = config.groupPassword;
117117
_isServerEncrypted = config.isServerEncrypted ? 'OPEN' : 'CLOSE';
118-
_communicationMethod = config.isTcp ? 'TCP' : 'UDP';
118+
_communicationMethod = config.protocol;
119119
_dataFingerprintVerification =
120120
config.dataFingerprintVerification ? 'OPEN' : 'CLOSE';
121121
_encryptionAlgorithm = config.encryptionAlgorithm;
@@ -196,7 +196,7 @@ class _NetworkConfigInputPageState extends State<NetworkConfigInputPage> {
196196
.toList(),
197197
groupPassword: _groupPasswordController.text,
198198
isServerEncrypted: _isServerEncrypted == 'OPEN',
199-
isTcp: _communicationMethod == 'TCP',
199+
protocol: _communicationMethod,
200200
dataFingerprintVerification: _dataFingerprintVerification == 'OPEN',
201201
encryptionAlgorithm: _encryptionAlgorithm,
202202
deviceID: _deviceIDController.text,
@@ -357,15 +357,17 @@ class _NetworkConfigInputPageState extends State<NetworkConfigInputPage> {
357357
last = stripPrefix(value, 'wss://');
358358
if (last != null) {
359359
_communicationMethod = 'WSS';
360+
} else {
361+
_communicationMethod = 'UDP';
360362
}
361363
}
362364
}
363365
}
366+
setState(() {
367+
_communicationMethod;
368+
});
364369
if (last != null) {
365370
value = last;
366-
setState(() {
367-
_communicationMethod;
368-
});
369371
}
370372
final txtRegex = RegExp(r'^txt:');
371373
final addressPortRegex = RegExp(r'^(.+):(\d{1,5})$');
@@ -384,6 +386,11 @@ class _NetworkConfigInputPageState extends State<NetworkConfigInputPage> {
384386
} else {
385387
final match = addressPortRegex.firstMatch(value);
386388
if (match != null) {
389+
final domainRegex =
390+
RegExp(r'^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$');
391+
if (!domainRegex.hasMatch(match.group(1)!)) {
392+
return '地址格式错误';
393+
}
387394
final port = int.tryParse(match.group(2)!);
388395
if (port != null && port >= 1 && port <= 65535) {
389396
return null;

lib/settings_page.dart

+14-13
Original file line numberDiff line numberDiff line change
@@ -305,20 +305,21 @@ class _SettingsPageState extends State<SettingsPage> {
305305
},
306306
),
307307
),
308-
ListTile(
309-
title: const Text('应用日志'),
310-
trailing: IconButton(
311-
icon: const Icon(Icons.sms_failed),
312-
onPressed: () {
313-
Navigator.push(
314-
context,
315-
MaterialPageRoute(
316-
builder: (context) => LogPage(),
317-
),
318-
);
319-
},
308+
if (!Platform.isAndroid)
309+
ListTile(
310+
title: const Text('应用日志'),
311+
trailing: IconButton(
312+
icon: const Icon(Icons.sms_failed),
313+
onPressed: () {
314+
Navigator.push(
315+
context,
316+
MaterialPageRoute(
317+
builder: (context) => LogPage(),
318+
),
319+
);
320+
},
321+
),
320322
),
321-
),
322323
],
323324
),
324325
);

0 commit comments

Comments
 (0)