diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8e1a8ddc..87c0de00 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -133,6 +133,7 @@ "repeatDelay": "Delay(ms)", "fixed": "fixed", "random": "random", + "keepCustomSettings": "Keep custom settings", "editRequest": "Edit and Request", "reSendRequest": "The request has been resent", "viewExport": "View Export", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 396b5250..ce61b28c 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -133,6 +133,7 @@ "repeatDelay": "延时(ms)", "fixed": "固定", "random": "重放", + "keepCustomSettings": "保持自定义设置", "editRequest": "编辑请求", "reSendRequest": "已重新发送请求", "viewExport": "视图导出", diff --git a/lib/network/http_client.dart b/lib/network/http_client.dart index a46361c9..2b3c9cf3 100644 --- a/lib/network/http_client.dart +++ b/lib/network/http_client.dart @@ -57,7 +57,7 @@ class HttpClients { await connectRequest(hostAndPort, channel); if (hostAndPort.isSsl()) { - await channel.secureSocket(channelContext); + await channel.secureSocket(channelContext, host: hostAndPort.host); } return channel; diff --git a/lib/ui/desktop/left/favorite.dart b/lib/ui/desktop/left/favorite.dart index 89862388..c63f33fe 100644 --- a/lib/ui/desktop/left/favorite.dart +++ b/lib/ui/desktop/left/favorite.dart @@ -19,6 +19,7 @@ import 'package:network_proxy/ui/content/panel.dart'; import 'package:network_proxy/ui/desktop/left/repeat.dart'; import 'package:network_proxy/utils/curl.dart'; import 'package:network_proxy/utils/python.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; /// @author wanghongen @@ -165,11 +166,14 @@ class _FavoriteItemState extends State<_FavoriteItem> { } //显示高级重发 - showCustomRepeat(HttpRequest request) { + showCustomRepeat(HttpRequest request) async { + var prefs = await SharedPreferences.getInstance(); + if (!mounted) return; + showDialog( context: context, builder: (BuildContext context) { - return CustomRepeatDialog(onRepeat: () => onRepeat(request)); + return CustomRepeatDialog(onRepeat: () => onRepeat(request), prefs: prefs); }); } diff --git a/lib/ui/desktop/left/repeat.dart b/lib/ui/desktop/left/repeat.dart index 5ec4e70f..64b436b3 100644 --- a/lib/ui/desktop/left/repeat.dart +++ b/lib/ui/desktop/left/repeat.dart @@ -1,16 +1,19 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:shared_preferences/shared_preferences.dart'; ///高级重放 /// @author wang class CustomRepeatDialog extends StatefulWidget { final Function onRepeat; + final SharedPreferences prefs; - const CustomRepeatDialog({super.key, required this.onRepeat}); + const CustomRepeatDialog({super.key, required this.onRepeat, required this.prefs}); @override State createState() => _CustomRepeatState(); @@ -24,9 +27,27 @@ class _CustomRepeatState extends State { TextEditingController delay = TextEditingController(text: '0'); bool fixed = true; + bool keepSetting = true; AppLocalizations get localizations => AppLocalizations.of(context)!; + @override + void initState() { + super.initState(); + + var customerRepeat = widget.prefs.getString('customerRepeat'); + keepSetting = customerRepeat != null; + if (customerRepeat != null) { + Map data = jsonDecode(customerRepeat); + count.text = data['count']; + interval.text = data['interval']; + minInterval.text = data['minInterval']; + maxInterval.text = data['maxInterval']; + delay.text = data['delay']; + fixed = data['fixed'] == true; + } + } + @override void dispose() { count.dispose(); @@ -46,7 +67,9 @@ class _CustomRepeatState extends State { child: ListBody( children: [ field(localizations.repeatCount, count), //次数 - Row( //间隔 + const SizedBox(height: 8), + Row( + //间隔 children: [ SizedBox(width: 75, child: Text(localizations.repeatInterval)), const SizedBox(height: 5), @@ -95,8 +118,21 @@ class _CustomRepeatState extends State { ]), ], ), - const SizedBox(height: 5), + const SizedBox(height: 8), field(localizations.repeatDelay, delay), //延时 + const SizedBox(height: 8), + //记录选择 + Row(mainAxisAlignment: MainAxisAlignment.start, children: [ + Text(localizations.keepCustomSettings), + Expanded( + child: Checkbox( + value: keepSetting, + onChanged: (val) { + setState(() { + keepSetting = val == true; + }); + })), + ]) ], ), )), @@ -111,6 +147,20 @@ class _CustomRepeatState extends State { if (!formKey.currentState!.validate()) { return; } + if (keepSetting) { + widget.prefs.setString( + 'customerRepeat', + jsonEncode({ + 'count': count.text, + 'interval': interval.text, + 'minInterval': minInterval.text, + 'maxInterval': maxInterval.text, + 'delay': delay.text, + 'fixed': fixed + })); + } else { + widget.prefs.remove('customerRepeat'); + } //定时发起请求 Future.delayed(Duration(milliseconds: int.parse(delay.text)), () => submitTask(int.parse(count.text))); @@ -152,21 +202,23 @@ class _CustomRepeatState extends State { ); } - FormField textField(TextEditingController? controller, {TextStyle? style}) { + Widget textField(TextEditingController? controller, {TextStyle? style}) { Color color = Theme.of(context).colorScheme.primary; - return TextFormField( - controller: controller, - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - style: style, - decoration: InputDecoration( - errorStyle: const TextStyle(height: 2, fontSize: 0), - contentPadding: const EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 5), - border: OutlineInputBorder(borderSide: BorderSide(width: 1, color: color.withOpacity(0.3))), - enabledBorder: OutlineInputBorder(borderSide: BorderSide(width: 1.5, color: color.withOpacity(0.5))), - focusedBorder: OutlineInputBorder(borderSide: BorderSide(width: 2, color: color))), - validator: (val) => val == null || val.isEmpty ? localizations.cannotBeEmpty : null, - ); + return ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 42), + child: TextFormField( + controller: controller, + keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + style: style, + decoration: InputDecoration( + errorStyle: const TextStyle(height: 2, fontSize: 0), + contentPadding: const EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 5), + border: OutlineInputBorder(borderSide: BorderSide(width: 1, color: color.withOpacity(0.3))), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(width: 1.5, color: color.withOpacity(0.5))), + focusedBorder: OutlineInputBorder(borderSide: BorderSide(width: 2, color: color))), + validator: (val) => val == null || val.isEmpty ? localizations.cannotBeEmpty : null, + )); } } diff --git a/lib/ui/desktop/left/request.dart b/lib/ui/desktop/left/request.dart index c59a92cc..cc39e2fe 100644 --- a/lib/ui/desktop/left/request.dart +++ b/lib/ui/desktop/left/request.dart @@ -21,6 +21,7 @@ import 'package:network_proxy/ui/desktop/left/repeat.dart'; import 'package:network_proxy/utils/curl.dart'; import 'package:network_proxy/utils/lang.dart'; import 'package:network_proxy/utils/python.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; /// 请求 URI @@ -247,11 +248,14 @@ class _RequestWidgetState extends State { } //显示高级重发 - showCustomRepeat(HttpRequest request) { + showCustomRepeat(HttpRequest request) async { + var prefs = await SharedPreferences.getInstance(); + if (!mounted) return; + showDialog( context: context, builder: (BuildContext context) { - return CustomRepeatDialog(onRepeat: () => onRepeat(request)); + return CustomRepeatDialog(onRepeat: () => onRepeat(request), prefs: prefs); }); } diff --git a/lib/ui/mobile/request/favorite.dart b/lib/ui/mobile/request/favorite.dart index abac3448..cc13d63a 100644 --- a/lib/ui/mobile/request/favorite.dart +++ b/lib/ui/mobile/request/favorite.dart @@ -16,6 +16,7 @@ import 'package:network_proxy/ui/mobile/request/repeat.dart'; import 'package:network_proxy/ui/mobile/request/request_editor.dart'; import 'package:network_proxy/utils/curl.dart'; import 'package:network_proxy/utils/python.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class MobileFavorites extends StatefulWidget { final ProxyServer proxyServer; @@ -181,8 +182,9 @@ class _FavoriteItemState extends State<_FavoriteItem> { //显示高级重发 showCustomRepeat(HttpRequest request) { Navigator.of(context).pop(); - Navigator.of(context) - .push(MaterialPageRoute(builder: (context) => MobileCustomRepeat(onRepeat: () => onRepeat(request)))); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => futureWidget(SharedPreferences.getInstance(), + (prefs) => MobileCustomRepeat(onRepeat: () => onRepeat(request), prefs: prefs)))); } onRepeat(HttpRequest request) { diff --git a/lib/ui/mobile/request/repeat.dart b/lib/ui/mobile/request/repeat.dart index dabfaabc..22ad89b4 100644 --- a/lib/ui/mobile/request/repeat.dart +++ b/lib/ui/mobile/request/repeat.dart @@ -1,16 +1,19 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:shared_preferences/shared_preferences.dart'; ///高级重放 /// @author wang class MobileCustomRepeat extends StatefulWidget { final Function onRepeat; + final SharedPreferences prefs; - const MobileCustomRepeat({super.key, required this.onRepeat}); + const MobileCustomRepeat({super.key, required this.onRepeat, required this.prefs}); @override State createState() => _CustomRepeatState(); @@ -24,9 +27,27 @@ class _CustomRepeatState extends State { TextEditingController delay = TextEditingController(text: '0'); bool fixed = true; + bool keepSetting = true; AppLocalizations get localizations => AppLocalizations.of(context)!; + @override + void initState() { + super.initState(); + + var customerRepeat = widget.prefs.getString('customerRepeat'); + keepSetting = customerRepeat != null; + if (customerRepeat != null) { + Map data = jsonDecode(customerRepeat); + count.text = data['count']; + interval.text = data['interval']; + minInterval.text = data['minInterval']; + maxInterval.text = data['maxInterval']; + delay.text = data['delay']; + fixed = data['fixed'] == true; + } + } + @override void dispose() { count.dispose(); @@ -49,6 +70,21 @@ class _CustomRepeatState extends State { if (!formKey.currentState!.validate()) { return; } + if (keepSetting) { + widget.prefs.setString( + 'customerRepeat', + jsonEncode({ + 'count': count.text, + 'interval': interval.text, + 'minInterval': minInterval.text, + 'maxInterval': maxInterval.text, + 'delay': delay.text, + 'fixed': fixed + })); + } else { + widget.prefs.remove('customerRepeat'); + } + Future.delayed(Duration(milliseconds: int.parse(delay.text)), () => submitTask(int.parse(count.text))); Navigator.of(context).pop(); }, @@ -66,6 +102,19 @@ class _CustomRepeatState extends State { intervalWidget(), //间隔 const SizedBox(height: 6), field(localizations.repeatDelay, delay), //延时 + const SizedBox(height: 6), + //记录选择 + Row(children: [ + Text(localizations.keepCustomSettings), + Expanded( + child: Checkbox( + value: keepSetting, + onChanged: (val) { + setState(() { + keepSetting = val == true; + }); + })), + ]) ], ), ))); diff --git a/lib/ui/mobile/request/request.dart b/lib/ui/mobile/request/request.dart index 0b805016..e035d757 100644 --- a/lib/ui/mobile/request/request.dart +++ b/lib/ui/mobile/request/request.dart @@ -19,6 +19,7 @@ import 'package:network_proxy/ui/mobile/widgets/highlight.dart'; import 'package:network_proxy/utils/curl.dart'; import 'package:network_proxy/utils/lang.dart'; import 'package:network_proxy/utils/navigator.dart'; +import 'package:shared_preferences/shared_preferences.dart'; ///请求行 class RequestRow extends StatefulWidget { @@ -212,8 +213,9 @@ class RequestRowState extends State { //显示高级重发 showCustomRepeat(HttpRequest request) { NavigatorHelper.pop(); - NavigatorHelper.push( - MaterialPageRoute(builder: (context) => MobileCustomRepeat(onRepeat: () => onRepeat(request)))); + NavigatorHelper.push(MaterialPageRoute( + builder: (context) => futureWidget(SharedPreferences.getInstance(), + (prefs) => MobileCustomRepeat(onRepeat: () => onRepeat(request), prefs: prefs)))); } onRepeat(HttpRequest request) { diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6c666872..f27b94a3 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -14,6 +14,7 @@ import path_provider_foundation import proxy_manager import screen_retriever import share_plus +import shared_preferences_foundation import url_launcher_macos import window_manager @@ -27,6 +28,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ProxyManagerPlugin.register(with: registry.registrar(forPlugin: "ProxyManagerPlugin")) ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) } diff --git a/pubspec.yaml b/pubspec.yaml index a4af5850..6f32ed76 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: flutter_desktop_context_menu: ^0.2.0 win32audio: ^1.3.1 device_info_plus: ^10.1.0 + shared_preferences: ^2.2.3 dev_dependencies: flutter_test: