1+ import 'dart:io' ;
2+
13import 'package:fluent_ui/fluent_ui.dart' ;
24import 'package:flutter_hooks/flutter_hooks.dart' ;
35import 'package:nat_tester/value_formatters.dart' ;
46import 'package:nat_tester/widgets/editable_combo_action_tile.dart' ;
57import 'package:nat_tester/widgets/expander_section.dart' ;
68import 'package:nat_tester/widgets/number_field_tile.dart' ;
79import 'package:nat_tester/widgets/read_only_value_tile.dart' ;
10+ import 'package:nat_tester/widgets/select_field_tile.dart' ;
811import 'package:nat_tester/widgets/switch_tile.dart' ;
912import 'package:nat_tester/widgets/text_field_tile.dart' ;
1013import 'package:stun/stun.dart' ;
1114
15+ enum _AddressFamilyOption {
16+ auto (null , '自动 (Auto)' ),
17+ ipv4 (InternetAddressType .IPv4 , 'IPv4' ),
18+ ipv6 (InternetAddressType .IPv6 , 'IPv6' );
19+
20+ const _AddressFamilyOption (this .type, this .label);
21+
22+ final InternetAddressType ? type;
23+ final String label;
24+
25+ @override
26+ String toString () => label;
27+ }
28+
1229class NatDiagnosticsPage extends HookWidget {
1330 static const int _maxLogEntries = 200 ;
1431
@@ -18,6 +35,7 @@ class NatDiagnosticsPage extends HookWidget {
1835 Widget build (BuildContext context) {
1936 final serverUri = useState <String >('stun:stun.hot-chilli.net:3478' );
2037 final localIp = useState <String >('' );
38+ final addressFamily = useState <_AddressFamilyOption >(_AddressFamilyOption .auto);
2139 final localPort = useState <int >(0 );
2240 final initialRtoMs = useState <int >(200 );
2341 final maxRetransmissions = useState <int >(2 );
@@ -102,6 +120,7 @@ class NatDiagnosticsPage extends HookWidget {
102120 localIp: localIp.value.isEmpty
103121 ? null
104122 : localIp.value,
123+ addressType: addressFamily.value.type,
105124 localPort: localPort.value,
106125 initialRto: Duration (
107126 milliseconds: initialRtoMs.value,
@@ -161,6 +180,17 @@ class NatDiagnosticsPage extends HookWidget {
161180 localIp.value = value;
162181 },
163182 ),
183+ SelectFieldTile <_AddressFamilyOption >(
184+ icon: FluentIcons .internet_sharing,
185+ title: '地址族选择 (Address Family)' ,
186+ description:
187+ '自动模式会跟随目标解析结果;选择 IPv4 或 IPv6 后,只使用对应地址族的 STUN 端点与 UDP socket。' ,
188+ options: _AddressFamilyOption .values,
189+ value: addressFamily.value,
190+ onChanged: (_AddressFamilyOption value) {
191+ addressFamily.value = value;
192+ },
193+ ),
164194 NumberFieldTile (
165195 icon: FluentIcons .plug_connected,
166196 title: '本地绑定端口 (Local Bind Port)' ,
@@ -465,3 +495,4 @@ String _formatLogEntry(StunLogEvent event) {
465495 final String level = event.level.name.toUpperCase ();
466496 return '[$timestamp ] [$level ] ${event .format ()}' ;
467497}
498+
0 commit comments