diff --git a/android/app/build.gradle b/android/app/build.gradle index da8605d..d1f731e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -57,6 +57,11 @@ android { release { // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug + + minifyEnabled true + shrinkResources true + + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..c282de6 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,8 @@ +#Flutter Wrapper +-keep class io.flutter.app.** { *; } +-keep class io.flutter.plugin.** { *; } +-keep class io.flutter.util.** { *; } +-keep class io.flutter.view.** { *; } +-keep class io.flutter.** { *; } +-keep class io.flutter.plugins.** { *; } +-keep class de.prosiebensat1digital.** { *; } \ No newline at end of file diff --git a/lib/network/util/script_manager.dart b/lib/network/util/script_manager.dart index 971b774..3e7636d 100644 --- a/lib/network/util/script_manager.dart +++ b/lib/network/util/script_manager.dart @@ -21,7 +21,7 @@ async function onRequest(context, request) { //request.headers["X-New-Headers"] = "My-Value"; // Update Body 使用fetch API请求接口,具体文档可网上搜索fetch API - //response.body = await fetch('https://www.baidu.com/').then(response => response.text()); + //request.body = await fetch('https://www.baidu.com/').then(response => response.text()); return request; } @@ -163,10 +163,10 @@ async function onResponse(context, request, response) { var context = jsonEncode(scriptContext(item)); var jsRequest = jsonEncode(convertJsRequest(request)); String script = await getScript(item); - var jsResult = await flutterJs.evaluateAsync( """var request = $jsRequest, context = $context; request['context'] = context; $script\n onRequest(context, request)"""); var result = await jsResultResolve(jsResult); + request.attributes['scriptContext'] = result['context']; return convertHttpRequest(request, result); } @@ -187,11 +187,10 @@ async function onResponse(context, request, response) { var context = jsonEncode(request.attributes['scriptContext'] ?? scriptContext(item)); var jsRequest = jsonEncode(convertJsRequest(request)); var jsResponse = jsonEncode(convertJsResponse(response)); - print(context); String script = await getScript(item); var jsResult = await flutterJs.evaluateAsync("""$script\n onResponse($context, $jsRequest,$jsResponse);"""); + // print("response: ${jsResult.isPromise} ${jsResult.isError} ${jsResult.rawResult}"); var result = await jsResultResolve(jsResult); - // print("response: ${jsResult.isPromise} ${jsResult.isError} $result"); return convertHttpResponse(response, result); } } @@ -204,10 +203,11 @@ async function onResponse(context, request, response) { jsResult = await flutterJs.handlePromise(jsResult); } var result = jsResult.rawResult; - if (Platform.isMacOS) { + if (Platform.isMacOS || Platform.isIOS) { result = flutterJs.convertValue(jsResult); } if (result is Future) { + flutterJs.executePendingJob(); result = await (jsResult.rawResult as Future); } if (result is String) { diff --git a/lib/storage/favorites.dart b/lib/storage/favorites.dart index 871bdc1..ef2569a 100644 --- a/lib/storage/favorites.dart +++ b/lib/storage/favorites.dart @@ -50,9 +50,9 @@ class FavoriteStorage { flushConfig(); } - static Future removeFavorite(HttpRequest request) async { + static Future removeFavorite(Favorite favorite) async { var list = await favorites; - list.remove(request); + list.remove(favorite); flushConfig(); } diff --git a/lib/ui/desktop/left/favorite.dart b/lib/ui/desktop/left/favorite.dart index 0883765..756d879 100644 --- a/lib/ui/desktop/left/favorite.dart +++ b/lib/ui/desktop/left/favorite.dart @@ -48,8 +48,8 @@ class _FavoritesState extends State { request, index: index, panel: widget.panel, - onRemove: (HttpRequest request) { - FavoriteStorage.removeFavorite(request); + onRemove: (Favorite favorite) { + FavoriteStorage.removeFavorite(favorite); FlutterToastr.show('已删除收藏', context); setState(() {}); }, @@ -68,7 +68,7 @@ class _FavoriteItem extends StatefulWidget { final int index; final Favorite favorite; final NetworkTabController panel; - final Function(HttpRequest request)? onRemove; + final Function(Favorite favorite)? onRemove; const _FavoriteItem(this.favorite, {Key? key, required this.panel, required this.onRemove, required this.index}) : super(key: key); @@ -148,7 +148,7 @@ class _FavoriteItemState extends State<_FavoriteItem> { }), const PopupMenuDivider(height: 0.3), popupItem("删除收藏", onTap: () { - widget.onRemove?.call(request); + widget.onRemove?.call(widget.favorite); }) ], ); diff --git a/lib/ui/desktop/toolbar/setting/script.dart b/lib/ui/desktop/toolbar/setting/script.dart index 02fb11b..090f250 100644 --- a/lib/ui/desktop/toolbar/setting/script.dart +++ b/lib/ui/desktop/toolbar/setting/script.dart @@ -294,10 +294,10 @@ class _ScriptEditState extends State { keyboardType: keyboardType, decoration: InputDecoration( hintText: hint, + contentPadding: const EdgeInsets.all(10), errorStyle: const TextStyle(height: 0, fontSize: 0), focusedBorder: focusedBorder(), isDense: true, - constraints: const BoxConstraints(maxHeight: 35), border: const OutlineInputBorder()), )) ]); diff --git a/lib/ui/mobile/connect_remote.dart b/lib/ui/mobile/connect_remote.dart index 074c619..0f8a696 100644 --- a/lib/ui/mobile/connect_remote.dart +++ b/lib/ui/mobile/connect_remote.dart @@ -5,6 +5,7 @@ import 'package:network_proxy/network/bin/configuration.dart'; import 'package:network_proxy/network/bin/server.dart'; import 'package:network_proxy/network/http_client.dart'; import 'package:network_proxy/network/util/host_filter.dart'; +import 'package:network_proxy/network/util/script_manager.dart'; class RemoteModel { final bool connect; @@ -102,16 +103,18 @@ class ConfigSyncState extends State { bool syncWhiteList = true; bool syncBlackList = true; bool syncRewrite = true; + bool syncScript = true; @override Widget build(BuildContext context) { return AlertDialog( title: const Text('同步配置', style: TextStyle(fontSize: 16)), content: SizedBox( - height: 230, + height: 260, child: Column( children: [ SwitchListTile( + dense: true, subtitle: const Text("同步白名单过滤"), value: syncWhiteList, onChanged: (val) { @@ -120,6 +123,7 @@ class ConfigSyncState extends State { }); }), SwitchListTile( + dense: true, subtitle: const Text("同步黑名单过滤"), value: syncBlackList, onChanged: (val) { @@ -128,6 +132,7 @@ class ConfigSyncState extends State { }); }), SwitchListTile( + dense: true, subtitle: const Text("同步请求重写"), value: syncRewrite, onChanged: (val) { @@ -135,6 +140,15 @@ class ConfigSyncState extends State { syncRewrite = val; }); }), + SwitchListTile( + dense: true, + subtitle: const Text("同步脚本"), + value: syncScript, + onChanged: (val) { + setState(() { + syncScript = val; + }); + }), ], )), actions: [ @@ -145,7 +159,7 @@ class ConfigSyncState extends State { }), TextButton( child: const Text('开始同步'), - onPressed: () { + onPressed: () async { if (syncWhiteList) { HostFilter.whitelist.load(widget.config['whitelist']); } @@ -156,9 +170,18 @@ class ConfigSyncState extends State { widget.configuration.requestRewrites.load(widget.config['requestRewrites']); widget.configuration.flushRequestRewriteConfig(); } + if (syncScript) { + await ScriptManager.instance.then((script) async { + script.list.clear(); + widget.config['scripts'].forEach((it) => script.addScript(ScriptItem.fromJson(it), it['script'])); + await script.flushConfig(); + }); + } widget.configuration.flushConfig(); - Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('同步成功'))); + if (mounted) { + Navigator.pop(context); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('同步成功'))); + } }), ], ); diff --git a/lib/ui/mobile/request/favorite.dart b/lib/ui/mobile/request/favorite.dart index b8e89e3..4356daa 100644 --- a/lib/ui/mobile/request/favorite.dart +++ b/lib/ui/mobile/request/favorite.dart @@ -46,8 +46,8 @@ class _FavoritesState extends State { return _FavoriteItem( favorite, index: index, - onRemove: (HttpRequest request) { - FavoriteStorage.removeFavorite(request); + onRemove: (Favorite favorite) { + FavoriteStorage.removeFavorite(favorite); FlutterToastr.show('已删除收藏', context); setState(() {}); }, @@ -67,7 +67,7 @@ class _FavoriteItem extends StatefulWidget { final int index; final Favorite favorite; final ProxyServer proxyServer; - final Function(HttpRequest request)? onRemove; + final Function(Favorite favorite)? onRemove; const _FavoriteItem(this.favorite, {Key? key, required this.onRemove, required this.proxyServer, required this.index}) : super(key: key); @@ -121,8 +121,8 @@ class _FavoriteItemState extends State<_FavoriteItem> { TextButton( child: const SizedBox(width: double.infinity, child: Text("重命名", textAlign: TextAlign.center)), onPressed: () { - rename(widget.favorite); Navigator.of(context).pop(); + rename(widget.favorite); }), const Divider(thickness: 0.5), TextButton( @@ -148,7 +148,7 @@ class _FavoriteItemState extends State<_FavoriteItem> { TextButton( child: const SizedBox(width: double.infinity, child: Text("删除收藏", textAlign: TextAlign.center)), onPressed: () { - widget.onRemove?.call(request); + widget.onRemove?.call(widget.favorite); FlutterToastr.show('删除成功', context); Navigator.of(context).pop(); }), diff --git a/lib/ui/mobile/setting/script.dart b/lib/ui/mobile/setting/script.dart index dcedbca..255f500 100644 --- a/lib/ui/mobile/setting/script.dart +++ b/lib/ui/mobile/setting/script.dart @@ -64,26 +64,25 @@ class _MobileScriptState extends State { _refreshScript(); }, )), - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - const SizedBox(width: 10), - FilledButton( - style: ElevatedButton.styleFrom(padding: const EdgeInsets.only(left: 20, right: 20)), - onPressed: scriptEdit, - child: const Text("添加"), - ), - const SizedBox(width: 10), - OutlinedButton( - style: ElevatedButton.styleFrom(padding: const EdgeInsets.only(left: 20, right: 20)), - onPressed: import, - child: const Text("导入"), - ) - ], - )), - const SizedBox(width: 15) ]), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + const SizedBox(width: 10), + FilledButton( + style: ElevatedButton.styleFrom(padding: const EdgeInsets.only(left: 20, right: 20)), + onPressed: scriptEdit, + child: const Text("添加"), + ), + const SizedBox(width: 10), + OutlinedButton( + style: ElevatedButton.styleFrom(padding: const EdgeInsets.only(left: 20, right: 20)), + onPressed: import, + child: const Text("导入"), + ), + const SizedBox(width: 15), + ], + ), const SizedBox(height: 5), Container( padding: const EdgeInsets.only(top: 10), @@ -98,7 +97,7 @@ class _MobileScriptState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Container( - width: 200, padding: const EdgeInsets.only(left: 10), child: const Text("名称")), + width: 100, padding: const EdgeInsets.only(left: 10), child: const Text("名称")), const SizedBox(width: 50, child: Text("启用", textAlign: TextAlign.center)), const VerticalDivider(), const Expanded(child: Text("URL")), @@ -228,11 +227,11 @@ class _ScriptEditState extends State { const Text("脚本:"), const SizedBox(height: 5), SizedBox( - height: 400, + height: 520, child: CodeTheme( data: CodeThemeData(styles: monokaiSublimeTheme), child: SingleChildScrollView( - child: CodeField(textStyle: const TextStyle(fontSize: 13), controller: script)))) + child: CodeField(textStyle: const TextStyle(fontSize: 14), controller: script)))) ], )))); } @@ -247,10 +246,10 @@ class _ScriptEditState extends State { keyboardType: keyboardType, decoration: InputDecoration( hintText: hint, + contentPadding: const EdgeInsets.all(10), errorStyle: const TextStyle(height: 0, fontSize: 0), focusedBorder: focusedBorder(), isDense: true, - constraints: const BoxConstraints(maxHeight: 38), border: const OutlineInputBorder()), )) ]); @@ -279,81 +278,83 @@ class _ScriptListState extends State { List rows(List list) { return List.generate(list.length, (index) { - return Ink( - child: GestureDetector( - onDoubleTap: () async { - String script = await (await ScriptManager.instance).getScript(list[index]); - if (!context.mounted) { - return; - } - Navigator.of(context) - .push(MaterialPageRoute(builder: (context) => ScriptEdit(scriptItem: list[index], script: script))) - .then((value) { - if (value != null) { + return InkWell( + onDoubleTap: () async { + String script = await (await ScriptManager.instance).getScript(list[index]); + if (!context.mounted) { + return; + } + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) => ScriptEdit(scriptItem: list[index], script: script))) + .then((value) { + if (value != null) { + setState(() {}); + } + }); + }, + onTapDown: (details) { + showContextMenu(context, details.globalPosition, items: [ + PopupMenuItem( + height: 35, + child: const Text("编辑"), + onTap: () async { + String script = await (await ScriptManager.instance).getScript(list[index]); + if (!context.mounted) { + return; + } + Navigator.of(context) + .push(MaterialPageRoute( + builder: (context) => ScriptEdit(scriptItem: list[index], script: script))) + .then((value) { + if (value != null) { + setState(() {}); + } + }); + }), + PopupMenuItem(height: 35, child: const Text("分享"), onTap: () => export(list[index])), + PopupMenuItem( + height: 35, + child: list[index].enabled ? const Text("禁用") : const Text("启用"), + onTap: () { + list[index].enabled = !list[index].enabled; setState(() {}); - } - }); - }, - onLongPressDown: (details) { - showContextMenu(context, details.globalPosition, items: [ - PopupMenuItem( - height: 35, - child: const Text("编辑"), - onTap: () async { - String script = await (await ScriptManager.instance).getScript(list[index]); - if (!context.mounted) { - return; - } - Navigator.of(context) - .push(MaterialPageRoute( - builder: (context) => ScriptEdit(scriptItem: list[index], script: script))) - .then((value) { - if (value != null) { - setState(() {}); - } - }); - }), - PopupMenuItem(height: 35, child: const Text("分享"), onTap: () => export(list[index])), - PopupMenuItem( - height: 35, - child: list[index].enabled ? const Text("禁用") : const Text("启用"), - onTap: () { - list[index].enabled = !list[index].enabled; - setState(() {}); - }), - const PopupMenuDivider(), - PopupMenuItem( - height: 35, - child: const Text("删除"), - onTap: () async { - (await ScriptManager.instance).removeScript(index); - _refreshScript(); - setState(() {}); - if (context.mounted) FlutterToastr.show('删除成功', context); - }), - ]); - }, - child: Container( - color: index.isEven ? Colors.grey.withOpacity(0.1) : null, - height: 30, - padding: const EdgeInsets.all(5), - child: Row( - children: [ - SizedBox(width: 200, child: Text(list[index].name!, style: const TextStyle(fontSize: 13))), - SizedBox( - width: 40, - child: Transform.scale( - scale: 0.65, - child: SwitchWidget( - value: list[index].enabled, - onChanged: (val) { - list[index].enabled = val; - _refreshScript(); - }))), - const SizedBox(width: 20), - Expanded(child: Text(list[index].url, style: const TextStyle(fontSize: 13))), - ], - )))); + }), + const PopupMenuDivider(), + PopupMenuItem( + height: 35, + child: const Text("删除"), + onTap: () async { + (await ScriptManager.instance).removeScript(index); + _refreshScript(); + setState(() {}); + if (context.mounted) FlutterToastr.show('删除成功', context); + }), + ]); + }, + child: Container( + color: index.isEven ? Colors.grey.withOpacity(0.1) : null, + height: 45, + padding: const EdgeInsets.all(5), + child: Row( + children: [ + SizedBox( + width: 100, + child: Text(list[index].name!, + style: const TextStyle(fontSize: 13), overflow: TextOverflow.ellipsis)), + SizedBox( + width: 50, + child: Transform.scale( + scale: 0.8, + child: SwitchWidget( + value: list[index].enabled, + onChanged: (val) { + list[index].enabled = val; + _refreshScript(); + }))), + const SizedBox(width: 10), + Expanded(child: Text(list[index].url, style: const TextStyle(fontSize: 13))), + ], + ))); }); } diff --git a/pubspec.lock b/pubspec.lock index 34f2678..62f023c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -405,10 +405,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.flutter-io.cn" source: hosted - version: "1.10.0" + version: "1.9.1" mime: dependency: transitive description: @@ -730,10 +730,10 @@ packages: dependency: transitive description: name: web - sha256: "14f1f70c51119012600c5f1f60ca68efda5a9b6077748163c6af2893ec5df8fc" + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.1-beta" + version: "0.1.4-beta" win32: dependency: transitive description: @@ -759,5 +759,5 @@ packages: source: hosted version: "1.0.3" sdks: - dart: ">=3.2.0-157.0.dev <4.0.0" + dart: ">=3.1.0 <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 459ede8..210c8f0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,8 @@ name: network_proxy -description: network proxy +description: ProxyPin publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.3+1 +version: 1.0.4+1 environment: sdk: '>=3.0.2 <4.0.0'