import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:winui_n2n/edge_state.dart'; import 'package:winui_n2n/saved_connection.dart'; import 'package:winui_n2n/shared_pref_singleton.dart'; TextEditingController _supernodeController = TextEditingController(); TextEditingController _communityController = TextEditingController(); TextEditingController _keyController = TextEditingController(); TextEditingController _selfAddressController = TextEditingController(); TextEditingController _configNameController = TextEditingController(); class ControlPage extends StatefulWidget { const ControlPage({super.key}); @override State createState() => _ControlPageState(); } class _ControlPageState extends State { bool _edgeConnecting = false; @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( width: 300, child: TextField( controller: _supernodeController, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: '主服务器', ), ), ), ), Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( width: 300, child: TextField( controller: _communityController, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: '网络社区', ), ), ), ), Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( width: 300, child: TextField( controller: _keyController, obscureText: true, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: '社区密码', ), ), ), ), Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( width: 300, child: TextField( controller: _selfAddressController, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: '我的地址', ), ), ), ), Padding( padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: () => showDialog( context: context, builder: (BuildContext context) => Dialog( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 350, child: TextField( controller: _configNameController, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: '给这个配置备注一个名字', ), ), ), const SizedBox(height: 15), Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ TextButton( onPressed: () { List nodeList = jsonDecode( SharedPrefSingleton().savedConnection); List nodes = nodeList .cast>() .map((nodeData) => SavedConnection.fromJson(nodeData)) .toList(); nodes.add(SavedConnection( _configNameController.text, _supernodeController.text, _communityController.text, _keyController.text, _selfAddressController.text, )); List> nodeMaps = nodes .map((node) => node.toJson()) .toList(); String jsonString = jsonEncode(nodeMaps); SharedPrefSingleton() .setSavedConnection(jsonString); Navigator.pop(context); return; }, child: const Text("保存")), TextButton( onPressed: () { Navigator.pop(context); return; }, child: const Text('取消'), ), ], ), ], ), ), ), ), child: const Text('保存配置'), ), ElevatedButton( onPressed: _edgeConnecting ? null : () async { if (EdgeState.instance.isRunning) { // Turn on firewall if (SharedPrefSingleton().autoFirewall) { await Process.run( "netsh.exe", [ "advfirewall", "set", "allprofiles", "state", "on", ], ); } // Kill the edge process if (EdgeState.instance.process != null) { if (EdgeState.instance.process!.kill()) { EdgeState.instance.isRunning = false; EdgeState.instance.process = null; setState(() {}); } } } else if (!EdgeState.instance.isRunning) { // Block user click setState(() { _edgeConnecting = true; }); // Check for tap device final findTapResult = await Process.run( "./tools/driver/devcon.exe", ["hwids", "tap0901"], ); if (findTapResult.stdout .toString() .contains('No matching devices found.')) { // Install tap device EdgeState.instance.logger .addLog("Tap device not found, installing tap"); debugPrint("Tap device not found, installing tap"); final installTapResult = await Process.run( "./tools/driver/devcon.exe", [ "install", "./tools/driver/OemVista.inf", "tap0901", ], ); if (installTapResult.stdout.toString().contains( "Tap driver installed successfully.") || installTapResult.stdout.toString().contains( "Drivers installed successfully.")) { EdgeState.instance.logger .addLog("Tap driver installed successfully."); debugPrint("Tap driver installed successfully."); } else { EdgeState.instance.logger .addLog("Tap driver install failed."); debugPrint("Tap driver install failed."); } } else { // Ignore. EdgeState.instance.logger .addLog("Tap device already installed"); debugPrint("Tap device already installed"); } // Close firewall if (SharedPrefSingleton().autoFirewall) { await Process.run( "netsh.exe", [ "advfirewall", "set", "allprofiles", "state", "off", ], ); } // Start the edge // edge -c -k -a -r -l Process.start( "./tools/edge/edge.exe", [ "-l", _supernodeController.text, "-c", _communityController.text, "-k", _keyController.text, "-a", _selfAddressController.text, "-r", ], ).then((process) async { EdgeState.instance.isRunning = true; EdgeState.instance.process = process; EdgeState.instance.logger .addLog("edge.exe starting"); debugPrint("edge.exe starting"); setState(() { _edgeConnecting = false; }); process.stdout .transform(const SystemEncoding().decoder) .listen((data) { debugPrint('stdout: $data'); EdgeState.instance.logger.addLog(data); }); await process.exitCode; EdgeState.instance.isRunning = false; EdgeState.instance.process = null; EdgeState.instance.logger .addLog("edge.exe closing"); debugPrint("edge.exe closing"); if (!mounted) return; setState(() {}); }); } }, child: EdgeState.instance.isRunning ? const Text("断开连接") : const Text("开始连接"), ), TextButton( onPressed: () { SavedConnection? selectedSavedConnection; showDialog( context: context, builder: (BuildContext context) => Dialog( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Builder(builder: (context) { String jsonString = SharedPrefSingleton().savedConnection; List nodeList = jsonDecode(jsonString); List nodes = nodeList .cast>() .map((nodeData) => SavedConnection.fromJson(nodeData)) .toList(); return StatefulBuilder(builder: (BuildContext context, StateSetter setState) { return DropdownButton( value: selectedSavedConnection, items: nodes.map< DropdownMenuItem< SavedConnection>>( (SavedConnection value) { return DropdownMenuItem< SavedConnection>( value: value, child: Text(value.name), ); }).toList(), onChanged: (value) { setState( () { selectedSavedConnection = value!; }, ); }); }); }), const SizedBox(height: 15), Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: () { if (selectedSavedConnection != null) { _supernodeController.text = selectedSavedConnection!.supernode; _communityController.text = selectedSavedConnection!.community; _keyController.text = selectedSavedConnection! .communityKey; _selfAddressController.text = selectedSavedConnection! .selfAddress; } Navigator.pop(context); return; }, child: const Text('使用'), ), TextButton( onPressed: () { if (selectedSavedConnection == null) { Navigator.pop(context); return; } String jsonString = SharedPrefSingleton().savedConnection; List nodeList = jsonDecode(jsonString); List nodes = nodeList .cast>() .map((nodeData) => SavedConnection.fromJson( nodeData)) .toList(); nodes.removeWhere( (element) { return element.name == selectedSavedConnection!.name; }, ); List> nodeMaps = nodes .map((node) => node.toJson()) .toList(); SharedPrefSingleton() .setSavedConnection( jsonEncode(nodeMaps)) .then((onValue) { Navigator.pop(context); return; }); }, child: const Text('删除'), ), TextButton( onPressed: () { Navigator.pop(context); return; }, child: const Text("取消"), ), ], ), ], ), ), ), ); }, child: const Text("使用配置")), ], ), ), ], ); } }