part of 'settings_page.dart'; class NetworkSettings extends StatefulWidget { const NetworkSettings({super.key}); @override State createState() => _NetworkSettingsState(); } class _NetworkSettingsState extends State { @override Widget build(BuildContext context) { return SmoothCustomScrollView( slivers: [ SliverAppbar(title: Text("Network".tl)), _PopupWindowSetting( title: "Proxy".tl, builder: () => const _ProxySettingView(), ).toSliver(), _SliderSetting( title: "Download Threads".tl, settingsIndex: 'downloadThreads', interval: 1, min: 1, max: 16, ).toSliver(), ], ); } } class _ProxySettingView extends StatefulWidget { const _ProxySettingView(); @override State<_ProxySettingView> createState() => _ProxySettingViewState(); } class _ProxySettingViewState extends State<_ProxySettingView> { String type = ''; String host = ''; String port = ''; String username = ''; String password = ''; bool ignoreCertificateErrors = false; // USERNAME:PASSWORD@HOST:PORT String toProxyStr() { if (type == 'direct') { return 'direct'; } else if (type == 'system') { return 'system'; } var res = ''; if (username.isNotEmpty) { res += username; if (password.isNotEmpty) { res += ':$password'; } res += '@'; } res += host; if (port.isNotEmpty) { res += ':$port'; } return res; } void parseProxyString(String proxy) { if (proxy == 'direct') { type = 'direct'; return; } else if (proxy == 'system') { type = 'system'; return; } type = 'manual'; var parts = proxy.split('@'); if (parts.length == 2) { var auth = parts[0].split(':'); if (auth.length == 2) { username = auth[0]; password = auth[1]; } parts = parts[1].split(':'); if (parts.length == 2) { host = parts[0]; port = parts[1]; } } else { parts = proxy.split(':'); if (parts.length == 2) { host = parts[0]; port = parts[1]; } } } @override void initState() { var proxy = appdata.settings['proxy']; parseProxyString(proxy); ignoreCertificateErrors = appdata.settings['ignoreCertificateErrors'] ?? false; super.initState(); } @override Widget build(BuildContext context) { return PopUpWidgetScaffold( title: "Proxy".tl, body: SingleChildScrollView( child: Column( children: [ RadioListTile( title: Text("Direct".tl), value: 'direct', groupValue: type, onChanged: (v) { setState(() { type = v!; }); appdata.settings['proxy'] = toProxyStr(); appdata.saveData(); }, ), RadioListTile( title: Text("System".tl), value: 'system', groupValue: type, onChanged: (v) { setState(() { type = v!; }); appdata.settings['proxy'] = toProxyStr(); appdata.saveData(); }, ), RadioListTile( title: Text("Manual".tl), value: 'manual', groupValue: type, onChanged: (v) { setState(() { type = v!; }); }, ), if (type == 'manual') buildManualProxy(), SwitchListTile( title: Text("Ignore Certificate Errors".tl), value: ignoreCertificateErrors, onChanged: (v) { setState(() { ignoreCertificateErrors = v; }); appdata.settings['ignoreCertificateErrors'] = ignoreCertificateErrors; appdata.saveData(); }, ), ], ), ), ); } var formKey = GlobalKey(); Widget buildManualProxy() { return Form( key: formKey, child: Column( children: [ TextFormField( decoration: InputDecoration( border: const OutlineInputBorder(), labelText: "Host".tl, ), controller: TextEditingController(text: host), onChanged: (v) { host = v; }, validator: (v) { if (v?.isEmpty ?? false) { return "Host cannot be empty".tl; } return null; }, ), const SizedBox(height: 8), TextFormField( decoration: InputDecoration( border: const OutlineInputBorder(), labelText: "Port".tl, ), controller: TextEditingController(text: port), onChanged: (v) { port = v; }, validator: (v) { if (v?.isEmpty ?? true) { return null; } if (int.tryParse(v!) == null) { return "Port must be a number".tl; } return null; }, ), const SizedBox(height: 8), TextFormField( decoration: InputDecoration( border: const OutlineInputBorder(), labelText: "Username".tl, ), controller: TextEditingController(text: username), onChanged: (v) { username = v; }, validator: (v) { if ((v?.isEmpty ?? false) && password.isNotEmpty) { return "Username cannot be empty".tl; } return null; }, ), const SizedBox(height: 8), TextFormField( decoration: InputDecoration( border: const OutlineInputBorder(), labelText: "Password".tl, ), controller: TextEditingController(text: password), onChanged: (v) { password = v; }, ), const SizedBox(height: 16), FilledButton( onPressed: () { if (formKey.currentState?.validate() ?? false) { appdata.settings['proxy'] = toProxyStr(); appdata.saveData(); App.rootContext.pop(); } }, child: Text("Save".tl), ), ], ), ).paddingHorizontal(16).paddingTop(16); } }