diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8f073f7..cc31ab0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -72,8 +72,8 @@ "type": "Type", "enable": "Enable", "example": "Example: ", - "responseHeader": "Response Header", - "requestHeader": "Request Header", + "responseHeader": "Headers", + "requestHeader": "Headers", "requestLine": "Request Line", "requestMethod": "Request Method", "param": "Param", @@ -124,6 +124,7 @@ "deleteWhitelist": "Delete Proxy Whitelist", "domainListSubtitle": "Last Request Time: {time}, Count: {count}", + "selectAction": "Select action", "copy": "Copy", "copyHost": "Copy Host", "copyUrl": "Copy URL", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index ab23f09..db48564 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -124,12 +124,13 @@ "deleteWhitelist": "删除代理白名单", "domainListSubtitle": "最后请求时间: {time}, 次数: {count}", + "selectAction": "选择操作", "copy": "复制", "copyHost": "复制域名", "copyUrl": "复制URL", "copyRequestResponse": "复制 请求和响应", - "copyCurl": "复制 cURL 请求", - "copyAsPythonRequests": "复制 Python Requests 请求", + "copyCurl": "复制 cURL", + "copyAsPythonRequests": "复制 Python Requests", "delete": "删除", "rename": "重命名", "repeat": "重放", @@ -153,7 +154,7 @@ "keyword": "关键词", "keywordSearchScope": "关键词搜索范围: ", - "favorite": "收藏请求", + "favorite": "收藏", "deleteFavorite": "删除收藏", "emptyFavorite": "暂无收藏", "deleteFavoriteSuccess": "已删除收藏", diff --git a/lib/ui/component/share.dart b/lib/ui/component/share.dart index cb3110f..d989141 100644 --- a/lib/ui/component/share.dart +++ b/lib/ui/component/share.dart @@ -2,14 +2,10 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:flutter_js/quickjs/ffi.dart'; import 'package:flutter_toastr/flutter_toastr.dart'; import 'package:network_proxy/network/bin/server.dart'; -import 'package:network_proxy/network/components/script_manager.dart'; import 'package:network_proxy/network/http/http.dart'; import 'package:network_proxy/ui/component/utils.dart'; -import 'package:network_proxy/ui/mobile/request/request_editor.dart'; -import 'package:network_proxy/ui/mobile/setting/script.dart'; import 'package:network_proxy/utils/curl.dart'; import 'package:share_plus/share_plus.dart'; @@ -25,67 +21,46 @@ class ShareWidget extends StatelessWidget { Widget build(BuildContext context) { AppLocalizations localizations = AppLocalizations.of(context)!; - return IconButton( - icon: const Icon(Icons.share), - onPressed: () { - showMenu(context: context, position: menuPosition(context), items: [ - PopupMenuItem( - child: Text(localizations.shareUrl), + return PopupMenuButton( + icon: const Icon(Icons.share, size: 24), + offset: const Offset(0, 30), + itemBuilder: (BuildContext context) { + return [ + PopupMenuItem( + child: Text(localizations.shareUrl), + onTap: () { + if (request == null) { + FlutterToastr.show("Request is empty", context); + return; + } + Share.share(request!.requestUrl, subject: localizations.proxyPinSoftware); + }, + ), + PopupMenuItem( + padding: const EdgeInsets.only(left: 10), + child: Text(localizations.shareRequestResponse), onTap: () { if (request == null) { FlutterToastr.show("Request is empty", context); return; } - Share.share(request!.requestUrl, subject: localizations.proxyPinSoftware); - }, - ), - PopupMenuItem( - child: Text(localizations.shareRequestResponse), - onTap: () { - if (request == null) { - FlutterToastr.show("Request is empty", context); - return; - } - var file = XFile.fromData(utf8.encode(copyRequest(request!, response)), - name: localizations.captureDetail, mimeType: "txt"); - Share.shareXFiles([file], fileNameOverrides: ['request.txt'], text: localizations.proxyPinSoftware); - }), - PopupMenuItem( - child: Text(localizations.shareCurl), - onTap: () { - if (request == null) { - return; - } - var text = curlRequest(request!); - var file = XFile.fromData(utf8.encode(text), name: "cURL.txt", mimeType: "txt"); - Share.shareXFiles([file], fileNameOverrides: ["cURL.txt"], text: localizations.proxyPinSoftware); - }), - PopupMenuItem( - child: Text(localizations.requestEdit), - onTap: () { - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => MobileRequestEditor(request: request, proxyServer: proxyServer))); - }); - }), - PopupMenuItem( - child: Text(localizations.script), - onTap: () { - WidgetsBinding.instance.addPostFrameCallback((_) async { - var scriptManager = await ScriptManager.instance; - - var url = '${request?.remoteDomain()}${request?.path()}'; - var scriptItem = (scriptManager).list.firstWhereOrNull((it) => it.url == url); - String? script = scriptItem == null ? null : await scriptManager.getScript(scriptItem); - - if (!context.mounted) return; - - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => - ScriptEdit(scriptItem: scriptItem, script: script, url: scriptItem?.url ?? url))); - }); - }), - ]); - }); + var file = XFile.fromData(utf8.encode(copyRequest(request!, response)), + name: localizations.captureDetail, mimeType: "txt"); + Share.shareXFiles([file], fileNameOverrides: ['request.txt'], text: localizations.proxyPinSoftware); + }), + PopupMenuItem( + padding: const EdgeInsets.only(left: 10), + child: Text(localizations.shareCurl), + onTap: () { + if (request == null) { + return; + } + var text = curlRequest(request!); + var file = XFile.fromData(utf8.encode(text), name: "cURL.txt", mimeType: "txt"); + Share.shareXFiles([file], fileNameOverrides: ["cURL.txt"], text: localizations.proxyPinSoftware); + }), + ]; + }, + ); } } diff --git a/lib/ui/component/toolbox.dart b/lib/ui/component/toolbox.dart index 1332a7e..0d8a686 100644 --- a/lib/ui/component/toolbox.dart +++ b/lib/ui/component/toolbox.dart @@ -90,7 +90,7 @@ class _ToolboxState extends State { onTap: () => encodeWindow(EncoderType.base64, context), child: Container( padding: const EdgeInsets.all(10), - child: const Column(children: [Icon(Icons.currency_bitcoin), SizedBox(height: 3), Text('Base64')]), + child: const Column(children: [Icon(Icons.format_bold), SizedBox(height: 3), Text('Base64')]), )), const SizedBox(width: 15), InkWell( diff --git a/lib/ui/component/widgets.dart b/lib/ui/component/widgets.dart index e372ac6..455e47c 100644 --- a/lib/ui/component/widgets.dart +++ b/lib/ui/component/widgets.dart @@ -10,6 +10,7 @@ class CustomPopupMenuItem extends PopupMenuItem { super.height, super.value, super.enabled, + super.padding, required Widget super.child, this.color, }); @@ -30,6 +31,28 @@ class _CustomPopupMenuItemState extends PopupMenuItemState false; + + @override + State createState() => _PopupMenuContainerState(); +} + +class _PopupMenuContainerState extends State { + @override + Widget build(BuildContext context) { + return widget.child; + } +} + class SwitchWidget extends StatefulWidget { final String? title; final String? subtitle; diff --git a/lib/ui/content/panel.dart b/lib/ui/content/panel.dart index a77803f..1527fa4 100644 --- a/lib/ui/content/panel.dart +++ b/lib/ui/content/panel.dart @@ -14,16 +14,24 @@ * limitations under the License. */ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_toastr/flutter_toastr.dart'; import 'package:network_proxy/network/bin/server.dart'; +import 'package:network_proxy/network/components/script_manager.dart'; import 'package:network_proxy/network/http/http.dart'; import 'package:network_proxy/network/http/websocket.dart'; +import 'package:network_proxy/storage/favorites.dart'; import 'package:network_proxy/ui/component/share.dart'; import 'package:network_proxy/ui/component/state_component.dart'; import 'package:network_proxy/ui/component/utils.dart'; +import 'package:network_proxy/ui/component/widgets.dart'; import 'package:network_proxy/ui/configuration.dart'; +import 'package:network_proxy/ui/mobile/request/request_editor.dart'; +import 'package:network_proxy/ui/mobile/setting/script.dart'; import 'package:network_proxy/utils/lang.dart'; import 'package:network_proxy/utils/platform.dart'; +import 'package:network_proxy/utils/python.dart'; import 'body.dart'; @@ -114,7 +122,61 @@ class NetworkTabState extends State with SingleTickerProvi bottom: tabBar, actions: [ ShareWidget( - proxyServer: widget.proxyServer, request: widget.request.get(), response: widget.response.get()) + proxyServer: widget.proxyServer, request: widget.request.get(), response: widget.response.get()), + const SizedBox(width: 3), + PopupMenuButton( + offset: const Offset(0, 30), + padding: const EdgeInsets.all(0), + itemBuilder: (context) => [ + PopupMenuItem( + child: Text(localizations.favorite), + onTap: () { + var request = widget.request.get(); + if (request == null) return; + + FavoriteStorage.addFavorite(request); + FlutterToastr.show(localizations.addSuccess, context); + }), + PopupMenuItem( + child: Text(localizations.requestEdit), + onTap: () { + WidgetsBinding.instance.addPostFrameCallback((_) { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => MobileRequestEditor( + request: widget.request.get(), proxyServer: widget.proxyServer))); + }); + }), + PopupMenuItem( + child: Text(localizations.script), + onTap: () { + WidgetsBinding.instance.addPostFrameCallback((_) async { + var scriptManager = await ScriptManager.instance; + var request = widget.request.get(); + var url = '${request?.remoteDomain()}${request?.path()}'; + var scriptItem = (scriptManager).list.firstWhereOrNull((it) => it.url == url); + String? script = scriptItem == null ? null : await scriptManager.getScript(scriptItem); + + if (!context.mounted) return; + + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => ScriptEdit( + scriptItem: scriptItem, script: script, url: scriptItem?.url ?? url))); + }); + }), + CustomPopupMenuItem( + padding: const EdgeInsets.only(left: 10), + child: Text(localizations.copyAsPythonRequests), + onTap: () { + var request = widget.request.get(); + if (request == null) return; + + var text = copyAsPythonRequests(request); + Clipboard.setData(ClipboardData(text: text)); + FlutterToastr.show(localizations.copied, context); + }) + ], + child: const SizedBox(height: 38, width: 38, child: Icon(Icons.more_vert, size: 28))), + const SizedBox(width: 10), ], ); diff --git a/lib/ui/desktop/toolbar/setting/request_rewrite.dart b/lib/ui/desktop/toolbar/setting/request_rewrite.dart index 55ca5bd..ef3e0a4 100644 --- a/lib/ui/desktop/toolbar/setting/request_rewrite.dart +++ b/lib/ui/desktop/toolbar/setting/request_rewrite.dart @@ -619,7 +619,7 @@ class _RuleAddDialogState extends State { decoration: InputDecoration( hintText: hint, hintStyle: TextStyle(color: Colors.grey.shade500, fontSize: 14), - contentPadding: const EdgeInsets.all(10), + contentPadding: const EdgeInsets.symmetric(horizontal: 5, vertical: 10), errorStyle: const TextStyle(height: 0, fontSize: 0), focusedBorder: focusedBorder(), isDense: true, diff --git a/lib/ui/mobile/menu/me.dart b/lib/ui/mobile/menu/me.dart index e5a9f15..8c17c01 100644 --- a/lib/ui/mobile/menu/me.dart +++ b/lib/ui/mobile/menu/me.dart @@ -102,6 +102,11 @@ class _MePageState extends State { navigator(context, MobileRequestRewrite(requestRewrites: requestRewrites)); } }), + ListTile( + title: Text(localizations.script), + leading: Icon(Icons.javascript_outlined, color: color), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + onTap: () => navigator(context, const MobileScript())), ListTile( title: Text(localizations.requestBlock), leading: Icon(Icons.block_flipped, color: color), @@ -112,11 +117,6 @@ class _MePageState extends State { navigator(context, MobileRequestBlock(requestBlockManager: requestBlockManager)); } }), - ListTile( - title: Text(localizations.script), - leading: Icon(Icons.code, color: color), - trailing: const Icon(Icons.arrow_forward_ios, size: 16), - onTap: () => navigator(context, const MobileScript())), ListTile( title: Text(localizations.setting), leading: Icon(Icons.settings_outlined, color: color), diff --git a/lib/ui/mobile/request/favorite.dart b/lib/ui/mobile/request/favorite.dart index 1a71e26..6cb9d35 100644 --- a/lib/ui/mobile/request/favorite.dart +++ b/lib/ui/mobile/request/favorite.dart @@ -32,7 +32,6 @@ 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/lang.dart'; -import 'package:network_proxy/utils/python.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// 收藏列表页面 @@ -164,8 +163,6 @@ class _FavoriteItemState extends State<_FavoriteItem> { const Divider(thickness: 0.5, height: 5), menuItem(localizations.copyCurl, () => curlRequest(request)), const Divider(thickness: 0.5, height: 5), - menuItem(localizations.copyAsPythonRequests, () => copyAsPythonRequests(request)), - const Divider(thickness: 0.5, height: 5), TextButton( child: SizedBox(width: double.infinity, child: Text(localizations.rename, textAlign: TextAlign.center)), onPressed: () { diff --git a/lib/ui/mobile/request/request.dart b/lib/ui/mobile/request/request.dart index c557783..95dee40 100644 --- a/lib/ui/mobile/request/request.dart +++ b/lib/ui/mobile/request/request.dart @@ -27,6 +27,7 @@ import 'package:network_proxy/network/http_client.dart'; import 'package:network_proxy/network/util/cache.dart'; import 'package:network_proxy/storage/favorites.dart'; import 'package:network_proxy/ui/component/utils.dart'; +import 'package:network_proxy/ui/component/widgets.dart'; import 'package:network_proxy/ui/content/panel.dart'; import 'package:network_proxy/ui/mobile/request/repeat.dart'; import 'package:network_proxy/ui/mobile/request/request_editor.dart'; @@ -94,33 +95,36 @@ class RequestRowState extends State { var highlightColor = KeywordHighlight.getHighlightColor(url); - return ListTile( - visualDensity: const VisualDensity(vertical: -4), - minLeadingWidth: 5, - selected: selected, - textColor: highlightColor, - selectedColor: highlightColor, - leading: appIcon(), - title: Text(title, overflow: TextOverflow.ellipsis, maxLines: 2, style: const TextStyle(fontSize: 14)), - subtitle: Text.rich( - maxLines: 1, - TextSpan(children: [ - TextSpan(text: '#${widget.index} ', style: const TextStyle(fontSize: 11, color: Colors.teal)), - TextSpan(text: subTitle, style: const TextStyle(fontSize: 11, color: Colors.grey)), - ])), - trailing: getIcon(response), - contentPadding: - Platform.isIOS ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.only(left: 3, right: 5), - onLongPress: menu, - onTap: () { - Navigator.of(context).push(MaterialPageRoute(builder: (context) { - return NetworkTabController( - proxyServer: widget.proxyServer, - httpRequest: request, - httpResponse: response, - title: Text(localizations.captureDetail, style: const TextStyle(fontSize: 16))); - })); - }); + return GestureDetector( + onLongPressStart: menu, + child: ListTile( + visualDensity: const VisualDensity(vertical: -4), + minLeadingWidth: 5, + selected: selected, + textColor: highlightColor, + selectedColor: highlightColor, + leading: appIcon(), + title: Text(title, overflow: TextOverflow.ellipsis, maxLines: 2, style: const TextStyle(fontSize: 14)), + subtitle: Text.rich( + maxLines: 1, + TextSpan(children: [ + TextSpan(text: '#${widget.index} ', style: const TextStyle(fontSize: 11, color: Colors.teal)), + TextSpan(text: subTitle, style: const TextStyle(fontSize: 11, color: Colors.grey)), + ])), + trailing: getIcon(response), + contentPadding: + Platform.isIOS ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.only(left: 3, right: 5), + onTap: () { + + Navigator.of(this.context).push(MaterialPageRoute(builder: (context) { + return NetworkTabController( + proxyServer: widget.proxyServer, + httpRequest: request, + httpResponse: response, + title: Text(localizations.captureDetail, style: const TextStyle(fontSize: 16))); + })); + }, + )); } Widget? appIcon() { @@ -149,78 +153,125 @@ class RequestRowState extends State { } ///菜单 - menu() { + menu(details) { setState(() { selected = true; }); - showModalBottomSheet( - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(10))), - context: context, - isScrollControlled: true, - enableDrag: true, - builder: (ctx) { - return Wrap(alignment: WrapAlignment.center, children: [ - menuCopyItem(localizations.copyUrl, () => widget.request.requestUrl), - const Divider(thickness: 0.5, height: 5), - menuCopyItem(localizations.copyCurl, () => curlRequest(widget.request)), - const Divider(thickness: 0.5, height: 5), - TextButton( - child: SizedBox(width: double.infinity, child: Text(localizations.repeat, textAlign: TextAlign.center)), - onPressed: () { - onRepeat(widget.request); - Navigator.maybePop(context); - }), - const Divider(thickness: 0.5, height: 5), - TextButton( - child: SizedBox( - width: double.infinity, child: Text(localizations.customRepeat, textAlign: TextAlign.center)), - onPressed: () => showCustomRepeat(widget.request)), - const Divider(thickness: 0.5, height: 5), - TextButton( - child: - SizedBox(width: double.infinity, child: Text(localizations.editRequest, textAlign: TextAlign.center)), - onPressed: () { - Navigator.maybePop(context); - var pageRoute = MaterialPageRoute( - builder: (context) => - MobileRequestEditor(request: widget.request, proxyServer: widget.proxyServer)); - if (mounted) { - Navigator.push(context, pageRoute); - } else { - NavigatorHelper.push(pageRoute); - } - }), - const Divider(thickness: 0.5, height: 5), - TextButton( - child: SizedBox(width: double.infinity, child: Text(localizations.favorite, textAlign: TextAlign.center)), - onPressed: () { - FavoriteStorage.addFavorite(widget.request); - FlutterToastr.show(localizations.addSuccess, context); - Navigator.maybePop(context); - }), - const Divider(thickness: 0.5, height: 5), - TextButton( - child: SizedBox(width: double.infinity, child: Text(localizations.delete, textAlign: TextAlign.center)), - onPressed: () { - widget.onRemove?.call(request); - FlutterToastr.show(localizations.deleteSuccess, context); - Navigator.maybePop(context); - }), - Container(color: Theme.of(context).hoverColor, height: 8), - TextButton( - child: Container( - height: 45, - width: double.infinity, - padding: const EdgeInsets.only(top: 10), - child: Text(localizations.cancel, textAlign: TextAlign.center)), - onPressed: () { - Navigator.maybePop(context); - }, - ), - ]); - }, - ).then((value) { + var globalPosition = details.globalPosition; + MediaQueryData mediaQuery = MediaQuery.of(context); + var position = RelativeRect.fromLTRB(globalPosition.dx, globalPosition.dy, globalPosition.dx, globalPosition.dy); + // Trigger haptic feedback + HapticFeedback.mediumImpact(); + showMenu( + context: context, + constraints: BoxConstraints(maxWidth: mediaQuery.size.width * 0.88), + position: position, + items: [ + //复制url + PopupMenuContainer( + child: Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.only(left: 20, top: 5), + child: Text(localizations.selectAction, style: Theme.of(context).textTheme.bodyLarge)), + ), + //copy + menuItem( + left: button( + onPressed: () { + Clipboard.setData(ClipboardData(text: request.requestUrl)).then((value) { + if (mounted) { + FlutterToastr.show(localizations.copied, context); + Navigator.maybePop(context); + } + }); + }, + label: localizations.copyUrl, + icon: Icons.link, + iconSize: 22), + right: button( + onPressed: () { + Clipboard.setData(ClipboardData(text: curlRequest(request))).then((value) { + if (mounted) { + FlutterToastr.show(localizations.copied, context); + Navigator.maybePop(context); + } + }); + }, + label: localizations.copyCurl, + icon: Icons.code), + ), + //repeat + menuItem( + left: button( + onPressed: () { + onRepeat(request); + Navigator.maybePop(context); + }, + label: localizations.repeat, + icon: Icons.repeat_one), + right: button( + onPressed: () => showCustomRepeat(request), label: localizations.customRepeat, icon: Icons.repeat), + ), + //favorite and edit + menuItem( + left: button( + onPressed: () { + FavoriteStorage.addFavorite(widget.request); + FlutterToastr.show(localizations.addSuccess, context); + Navigator.maybePop(context); + }, + label: localizations.favorite, + icon: Icons.favorite_outline), + right: button( + onPressed: () { + Navigator.pop(context); + + var pageRoute = MaterialPageRoute( + builder: (context) => + MobileRequestEditor(request: widget.request, proxyServer: widget.proxyServer)); + if (mounted) { + Navigator.push(context, pageRoute); + } else { + NavigatorHelper.push(pageRoute); + } + }, + label: localizations.editRequest, + icon: Icons.edit_outlined), + ), + + // menuItem( + // left: button( + // onPressed: () {}, label: localizations.script, icon: Icons.javascript_outlined, iconSize: 24), + // right: button(onPressed: () {}, label: localizations.requestRewrite, icon: Icons.replay_outlined), + // ), + // menuItem( + // left: TextButton.icon( + // onPressed: () {}, + // label: Text(localizations.highlight), + // icon: const Icon(Icons.highlight_outlined, size: 20)), + // right: TextButton.icon( + // onPressed: () {}, + // label: Text(localizations.requestRewrite), + // icon: const Icon(Icons.highlight_remove, size: 20)), + // ), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + button( + onPressed: () { + widget.onRemove?.call(request); + FlutterToastr.show(localizations.deleteSuccess, context); + Navigator.maybePop(context); + }, + label: localizations.delete, + icon: Icons.delete_outline), + SizedBox(width: 15), + ]), + ], + )), + ]).then((value) { selected = false; if (mounted) setState(() {}); }); @@ -228,7 +279,7 @@ class RequestRowState extends State { //显示高级重发 showCustomRepeat(HttpRequest request) { - Navigator.maybePop(context); + Navigator.pop(context); var pageRoute = MaterialPageRoute( builder: (context) => futureWidget(SharedPreferences.getInstance(), (prefs) => MobileCustomRepeat(onRepeat: () => onRepeat(request), prefs: prefs))); @@ -249,16 +300,18 @@ class RequestRowState extends State { } } - Widget menuCopyItem(String title, String Function() callback) { - return TextButton( - child: SizedBox(width: double.infinity, child: Text(title, textAlign: TextAlign.center)), - onPressed: () { - Clipboard.setData(ClipboardData(text: callback.call())).then((value) { - if (mounted) { - FlutterToastr.show(localizations.copied, context); - Navigator.maybePop(context); - } - }); - }); + Widget button({required String label, required IconData icon, required Function() onPressed, double iconSize = 20}) { + var style = Theme.of(context).textTheme.bodyMedium; + return TextButton.icon( + onPressed: onPressed, label: Text(label, style: style), icon: Icon(icon, size: iconSize, color: style?.color)); + } + + Widget menuItem({required Widget left, required Widget right}) { + return Row( + children: [ + SizedBox(width: 130, child: Align(alignment: Alignment.centerLeft, child: left)), + Expanded(child: Align(alignment: Alignment.centerLeft, child: right)) + ], + ); } } diff --git a/lib/ui/mobile/setting/request_rewrite.dart b/lib/ui/mobile/setting/request_rewrite.dart index 22c7f25..c04889b 100644 --- a/lib/ui/mobile/setting/request_rewrite.dart +++ b/lib/ui/mobile/setting/request_rewrite.dart @@ -494,7 +494,7 @@ class _RewriteRuleState extends State { child: ListView(children: [ Row(children: [ SizedBox( - width: 58, + width: 60, child: Text('${localizations.enable}:', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500))), SwitchWidget(value: rule.enabled, onChanged: (val) => rule.enabled = val, scale: 0.8) @@ -504,7 +504,7 @@ class _RewriteRuleState extends State { required: true, keyboardType: TextInputType.url), Row(children: [ SizedBox( - width: 58, + width: 60, child: Text('${localizations.action}:', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500))), SizedBox( @@ -546,7 +546,7 @@ class _RewriteRuleState extends State { Widget textField(String label, TextEditingController controller, String hint, {bool required = false, TextInputType? keyboardType, FormFieldSetter? onSaved}) { return Row(children: [ - SizedBox(width: 58, child: Text(label, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500))), + SizedBox(width: 60, child: Text(label, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500))), Expanded( child: TextFormField( controller: controller, @@ -556,7 +556,7 @@ class _RewriteRuleState extends State { decoration: InputDecoration( hintText: hint, hintStyle: TextStyle(color: Colors.grey.shade500), - contentPadding: const EdgeInsets.all(10), + contentPadding: const EdgeInsets.only(), errorStyle: const TextStyle(height: 0, fontSize: 0), ), )) diff --git a/lib/ui/mobile/setting/rewrite/rewrite_replace.dart b/lib/ui/mobile/setting/rewrite/rewrite_replace.dart index 85cd871..4070dce 100644 --- a/lib/ui/mobile/setting/rewrite/rewrite_replace.dart +++ b/lib/ui/mobile/setting/rewrite/rewrite_replace.dart @@ -347,9 +347,7 @@ class RewriteReplaceState extends State { Widget statusCodeEdit() { var rewriteItem = items.firstWhere((item) => item.type == RewriteType.replaceResponseStatus); - return Container( - padding: const EdgeInsets.all(10), - child: Column(children: [ + return Column(children: [ Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ Text(localizations.statusCode), const SizedBox(width: 10), @@ -379,7 +377,7 @@ class RewriteReplaceState extends State { ])), const SizedBox(width: 10), ]) - ])); + ]); } InputDecoration decoration(String label, {String? hintText}) {