mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-05-20 16:15:47 +08:00
新增请求动画效果
This commit is contained in:
@@ -37,13 +37,15 @@ class FluentApp extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ThemeData(brightness: Brightness.dark, useMaterial3: false);
|
||||
return ValueListenableBuilder<ThemeMode>(
|
||||
valueListenable: themeNotifier,
|
||||
builder: (_, ThemeMode currentMode, __) {
|
||||
return MaterialApp(
|
||||
title: 'ProxyPin',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData.light(useMaterial3: true),
|
||||
darkTheme: ThemeData(brightness: Brightness.dark, useMaterial3: false),
|
||||
darkTheme: ThemeData.dark(useMaterial3: false),
|
||||
themeMode: currentMode,
|
||||
home: const NetworkHomePage(),
|
||||
);
|
||||
@@ -59,37 +61,42 @@ class NetworkHomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _NetworkHomePagePageState extends State<NetworkHomePage> implements EventListener {
|
||||
final domainStateKey = GlobalKey<DomainWidgetState>();
|
||||
final NetworkTabController panel = NetworkTabController();
|
||||
late DomainWidget domainWidget;
|
||||
|
||||
late ProxyServer proxyServer;
|
||||
|
||||
@override
|
||||
void onRequest(Channel channel, HttpRequest request) {
|
||||
domainWidget.add(channel, request);
|
||||
domainStateKey.currentState!.add(channel, request);
|
||||
}
|
||||
|
||||
@override
|
||||
void onResponse(Channel channel, HttpResponse response) {
|
||||
domainWidget.addResponse(channel, response);
|
||||
domainStateKey.currentState!.addResponse(channel, response);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
domainWidget = DomainWidget(panel: panel);
|
||||
proxyServer = ProxyServer(listener: this);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
final domainWidget = DomainWidget(key: domainStateKey, panel: panel);
|
||||
|
||||
return Scaffold(
|
||||
appBar: Tab(
|
||||
child: Toolbar(proxyServer, domainWidget),
|
||||
child: Toolbar(proxyServer, domainStateKey),
|
||||
),
|
||||
body: Row(children: [
|
||||
SizedBox(width: 400, child: domainWidget),
|
||||
const VerticalDivider(),
|
||||
Expanded(flex: 100, child: domainWidget.panel),
|
||||
]));
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
SizedBox(width: 400, child: domainWidget),
|
||||
const VerticalDivider(),
|
||||
Expanded(flex: 100, child: panel),
|
||||
])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:network_proxy/utils/ip.dart';
|
||||
|
||||
class SystemProxy {
|
||||
/// 设置系统代理
|
||||
static void setSystemProxy(int port, bool enableSsl) async {
|
||||
@@ -18,12 +20,13 @@ class SystemProxy {
|
||||
}
|
||||
var host = match.namedGroup('host');
|
||||
var port = match.namedGroup('port');
|
||||
var name = await hardwarePort();
|
||||
var results = await Process.run('bash', [
|
||||
'-c',
|
||||
_concatCommands([
|
||||
'networksetup -setwebproxy wi-fi $host $port',
|
||||
enableSsl == true ? 'networksetup -setsecurewebproxy wi-fi $host $port' : '',
|
||||
'networksetup -setproxybypassdomains wi-fi 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 127.0.0.1, localhost, *.local, timestamp.apple.com, sequoia.apple.com, seed-sequoia.siri.apple.com, *.google.com, *.googleapis.com',
|
||||
'networksetup -setwebproxy $name $host $port',
|
||||
enableSsl == true ? 'networksetup -setsecurewebproxy $name $host $port' : '',
|
||||
'networksetup -setproxybypassdomains $name 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 127.0.0.1 localhost *.local timestamp.apple.com sequoia.apple.com seed-sequoia.siri.apple.com *.google.com',
|
||||
])
|
||||
]);
|
||||
print('set proxyServer, exitCode: ${results.exitCode}, stdout: ${results.stdout}');
|
||||
@@ -32,25 +35,65 @@ class SystemProxy {
|
||||
|
||||
static Future<bool> setProxyEnableMacOS(bool proxyEnable, bool enableSsl) async {
|
||||
var proxyMode = proxyEnable ? 'on' : 'off';
|
||||
var name = await hardwarePort();
|
||||
var results = await Process.run('bash', [
|
||||
'-c',
|
||||
_concatCommands([
|
||||
'networksetup -setwebproxystate wi-fi $proxyMode',
|
||||
enableSsl ? 'networksetup -setsecurewebproxystate wi-fi $proxyMode' : '',
|
||||
'networksetup -setwebproxystate $name $proxyMode',
|
||||
enableSsl ? 'networksetup -setsecurewebproxystate $name $proxyMode' : '',
|
||||
])
|
||||
]);
|
||||
return results.exitCode == 0;
|
||||
}
|
||||
|
||||
static Future<bool> setSslProxyEnableMacOS(bool proxyEnable, port) async {
|
||||
var name = await hardwarePort();
|
||||
|
||||
var results = await Process.run('bash', [
|
||||
'-c',
|
||||
proxyEnable
|
||||
? 'networksetup -setsecurewebproxy $name 127.0.0.1 $port'
|
||||
: 'networksetup -setsecurewebproxystate $name off',
|
||||
]);
|
||||
return results.exitCode == 0;
|
||||
}
|
||||
|
||||
static Future<String> hardwarePort() async {
|
||||
var name = await networkName();
|
||||
var results = await Process.run('bash', [
|
||||
'-c',
|
||||
_concatCommands([
|
||||
proxyEnable
|
||||
? 'networksetup -setsecurewebproxy wi-fi 127.0.0.1 $port'
|
||||
: 'networksetup -setsecurewebproxystate wi-fi off',
|
||||
'networksetup -listnetworkserviceorder |grep "Device: $name" -A 1 |grep "Hardware Port" |awk -F ": " \'{print \$2}\'',
|
||||
])
|
||||
]);
|
||||
|
||||
return results.stdout.toString().split(", ")[0];
|
||||
}
|
||||
|
||||
static Future<bool> _setProxyServerWindows(String proxyServer) async {
|
||||
var results = await Process.run('reg', [
|
||||
'add',
|
||||
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'/v',
|
||||
'ProxyServer',
|
||||
'/f',
|
||||
'/d',
|
||||
proxyServer,
|
||||
]);
|
||||
|
||||
Process.run('reg', [
|
||||
'add',
|
||||
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'/v',
|
||||
'ProxyOverride',
|
||||
'/t',
|
||||
'REG_SZ',
|
||||
'/d',
|
||||
'192.168.0.*;10.0.0.*;172.16.0.*;127.0.0.1;localhost;*.local',
|
||||
'/f',
|
||||
]);
|
||||
|
||||
print('set proxyServer $proxyServer, exitCode: ${results.exitCode}, stdout: ${results.stderr}');
|
||||
return results.exitCode == 0;
|
||||
}
|
||||
|
||||
@@ -69,21 +112,12 @@ class SystemProxy {
|
||||
return results.exitCode == 0;
|
||||
}
|
||||
|
||||
static Future<bool> _setProxyServerWindows(String proxyServer) async {
|
||||
var results = await Process.run('reg', [
|
||||
'add',
|
||||
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
'/v',
|
||||
'ProxyServer',
|
||||
'/f',
|
||||
'/d',
|
||||
proxyServer,
|
||||
]);
|
||||
print('set proxyServer $proxyServer, exitCode: ${results.exitCode}, stdout: ${results.stderr}');
|
||||
return results.exitCode == 0;
|
||||
}
|
||||
|
||||
static _concatCommands(List<String> commands) {
|
||||
return commands.where((element) => element.isNotEmpty).join(' && ');
|
||||
}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
var r = await SystemProxy.hardwarePort();
|
||||
print(r);
|
||||
}
|
||||
|
||||
@@ -1 +1,65 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorTransition extends StatefulWidget {
|
||||
final Color begin;
|
||||
final Color end;
|
||||
final Duration duration;
|
||||
final Widget child;
|
||||
|
||||
const ColorTransition({super.key, required this.begin, this.end = Colors.transparent,
|
||||
this.duration = const Duration(milliseconds: 500), required this.child});
|
||||
|
||||
@override
|
||||
State<ColorTransition> createState() {
|
||||
return ColorTransitionState();
|
||||
}
|
||||
}
|
||||
|
||||
class ColorTransitionState extends State<ColorTransition> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
late Animation _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
print("AnimationController");
|
||||
|
||||
//创建动画控制器
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: widget.duration,
|
||||
);
|
||||
|
||||
//添加动画执行刷新监听
|
||||
_animationController.addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
|
||||
//颜色动画变化
|
||||
_animation = ColorTween(begin: widget.begin, end: widget.end).animate(_animationController);
|
||||
|
||||
//添加到事件队列
|
||||
Future.delayed(const Duration(milliseconds: 80), () {
|
||||
_animationController.forward();
|
||||
});
|
||||
}
|
||||
|
||||
show() {
|
||||
_animationController.reset();
|
||||
_animationController.forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: _animation.value,
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:collection';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:network_proxy/network/http/http.dart';
|
||||
import 'package:network_proxy/ui/components.dart';
|
||||
import 'package:network_proxy/ui/left/path.dart';
|
||||
|
||||
import '../../network/channel.dart';
|
||||
@@ -12,42 +13,25 @@ import '../panel.dart';
|
||||
class DomainWidget extends StatefulWidget {
|
||||
final NetworkTabController panel;
|
||||
|
||||
DomainWidget({required this.panel}) : super(key: GlobalKey<_DomainWidgetState>());
|
||||
|
||||
void add(Channel channel, HttpRequest request) {
|
||||
var state = key as GlobalKey<_DomainWidgetState>;
|
||||
state.currentState?.add(channel, request);
|
||||
}
|
||||
|
||||
void addResponse(Channel channel, HttpResponse response) {
|
||||
var state = key as GlobalKey<_DomainWidgetState>;
|
||||
state.currentState?.addResponse(channel, response);
|
||||
}
|
||||
|
||||
void clean() {
|
||||
var state = key as GlobalKey<_DomainWidgetState>;
|
||||
panel.change(null, null);
|
||||
state.currentState?.clean();
|
||||
}
|
||||
const DomainWidget({super.key, required this.panel});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _DomainWidgetState();
|
||||
return DomainWidgetState();
|
||||
}
|
||||
}
|
||||
|
||||
class _DomainWidgetState extends State<DomainWidget> {
|
||||
class DomainWidgetState extends State<DomainWidget> {
|
||||
LinkedHashMap<HostAndPort, HeaderBody> containerMap = LinkedHashMap<HostAndPort, HeaderBody>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var list = containerMap.values;
|
||||
return ListView.builder(
|
||||
itemBuilder: (BuildContext context, int index) => list.elementAt(index), itemCount: list.length);
|
||||
return SingleChildScrollView(child: Column(children: list.toList()));
|
||||
}
|
||||
|
||||
///添加请求
|
||||
void add(Channel channel, HttpRequest request) {
|
||||
add(Channel channel, HttpRequest request) {
|
||||
HostAndPort hostAndPort = channel.getAttribute(AttributeKeys.host);
|
||||
HeaderBody? headerBody = containerMap[hostAndPort];
|
||||
var listURI = PathRow(request, widget.panel);
|
||||
@@ -64,14 +48,15 @@ class _DomainWidgetState extends State<DomainWidget> {
|
||||
}
|
||||
|
||||
///添加响应
|
||||
void addResponse(Channel channel, HttpResponse response) {
|
||||
addResponse(Channel channel, HttpResponse response) {
|
||||
HostAndPort hostAndPort = channel.getAttribute(AttributeKeys.host);
|
||||
HeaderBody? headerBody = containerMap[hostAndPort];
|
||||
headerBody?.getBody(channel.id)?.add(response);
|
||||
}
|
||||
|
||||
///清理
|
||||
void clean() {
|
||||
clean() {
|
||||
widget.panel.change(null, null);
|
||||
setState(() {
|
||||
containerMap.clear();
|
||||
});
|
||||
@@ -107,6 +92,8 @@ class HeaderBody extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _HeaderBodyState extends State<HeaderBody> {
|
||||
final GlobalKey<ColorTransitionState> transitionState = GlobalKey<ColorTransitionState>();
|
||||
|
||||
late bool selected;
|
||||
|
||||
@override
|
||||
@@ -117,6 +104,7 @@ class _HeaderBodyState extends State<HeaderBody> {
|
||||
|
||||
changeState() {
|
||||
setState(() {});
|
||||
transitionState.currentState?.show();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -128,16 +116,21 @@ class _HeaderBodyState extends State<HeaderBody> {
|
||||
}
|
||||
|
||||
Widget _hostWidget(String title) {
|
||||
return ListTile(
|
||||
leading: Icon(selected ? Icons.arrow_drop_down : Icons.arrow_right, size: 16),
|
||||
dense: true,
|
||||
horizontalTitleGap: 0,
|
||||
visualDensity: const VisualDensity(vertical: -3.6),
|
||||
title: Text(title, textAlign: TextAlign.left),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selected = !selected;
|
||||
});
|
||||
});
|
||||
return ColorTransition(
|
||||
key: transitionState,
|
||||
duration: const Duration(milliseconds: 1500),
|
||||
begin: Colors.white30,
|
||||
child: ListTile(
|
||||
minLeadingWidth: 25,
|
||||
leading: Icon(selected ? Icons.arrow_drop_down : Icons.arrow_right, size: 16),
|
||||
dense: true,
|
||||
horizontalTitleGap: 0,
|
||||
visualDensity: const VisualDensity(vertical: -3.6),
|
||||
title: Text(title, textAlign: TextAlign.left),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selected = !selected;
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ class _PathRowState extends State<PathRow> {
|
||||
var title = '${request.method.name} ${Uri.parse(request.uri).path}';
|
||||
var time = formatDate(request.requestTime, [HH, ':', nn, ':', ss]);
|
||||
return ListTile(
|
||||
minLeadingWidth: 25,
|
||||
leading: Icon(getIcon(), size: 16, color: widget.color),
|
||||
title: Text(title, overflow: TextOverflow.ellipsis, maxLines: 1),
|
||||
subtitle: Text(
|
||||
|
||||
@@ -16,22 +16,22 @@ class NetworkTabController extends StatefulWidget {
|
||||
final ValueWrap<HttpRequest> request = ValueWrap();
|
||||
final ValueWrap<HttpResponse> response = ValueWrap();
|
||||
|
||||
NetworkTabController() : super(key: GlobalKey<_NetworkTabState>());
|
||||
NetworkTabController() : super(key: GlobalKey<NetworkTabState>());
|
||||
|
||||
void change(HttpRequest? request, HttpResponse? response) {
|
||||
this.request.set(request);
|
||||
this.response.set(response);
|
||||
var state = key as GlobalKey<_NetworkTabState>;
|
||||
var state = key as GlobalKey<NetworkTabState>;
|
||||
state.currentState?.changeState();
|
||||
}
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _NetworkTabState();
|
||||
return NetworkTabState();
|
||||
}
|
||||
}
|
||||
|
||||
class _NetworkTabState extends State<NetworkTabController> {
|
||||
class NetworkTabState extends State<NetworkTabController> {
|
||||
void changeState() {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@@ -144,10 +144,10 @@ class _DomainFilterState extends State<DomainFilter> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
if (changed) {
|
||||
widget.proxyServer.flushConfig();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void add() {
|
||||
|
||||
@@ -26,23 +26,32 @@ class _SettingState extends State<Setting> {
|
||||
offset: const Offset(10, 30),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem<String>(child: PortWidget(proxyServer: widget.proxyServer)),
|
||||
PopupMenuItem<String>(padding: const EdgeInsets.all(0), child: PortWidget(proxyServer: widget.proxyServer)),
|
||||
const PopupMenuItem(
|
||||
padding: EdgeInsets.all(0),
|
||||
child: ThemeSetting(),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: ListTile(
|
||||
title: const Text("域名过滤"),
|
||||
dense: true,
|
||||
hoverColor: Colors.transparent,
|
||||
focusColor: Colors.transparent,
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () => _filter())),
|
||||
PopupMenuItem<String>(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: ListTile(
|
||||
title: const Text("请求重写"),
|
||||
dense: true,
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () => _reqeustRewrite())),
|
||||
title: const Text("请求重写"),
|
||||
dense: true,
|
||||
hoverColor: Colors.transparent,
|
||||
focusColor: Colors.transparent,
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () => _reqeustRewrite(),
|
||||
)),
|
||||
PopupMenuItem<String>(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: const ListTile(title: Text("Github"), dense: true, trailing: Icon(Icons.arrow_right)),
|
||||
onTap: () {
|
||||
launchUrl(Uri.parse("https://github.com/wanghongenpin/network-proxy-flutter"));
|
||||
|
||||
@@ -23,20 +23,26 @@ class _SslState extends State<SslWidget> {
|
||||
offset: const Offset(10, 30),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(child: _Switch(proxyServer: widget.proxyServer)),
|
||||
PopupMenuItem(padding: const EdgeInsets.all(0), child: _Switch(proxyServer: widget.proxyServer)),
|
||||
PopupMenuItem(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
title: const Text("安装根证书到系统"),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () {
|
||||
pcCer();
|
||||
},
|
||||
)),
|
||||
dense: true,
|
||||
hoverColor: Colors.transparent,
|
||||
focusColor: Colors.transparent,
|
||||
title: const Text("安装根证书到系统"),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () {
|
||||
pcCer();
|
||||
},
|
||||
)),
|
||||
PopupMenuItem<String>(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: ListTile(
|
||||
title: const Text("安装根证书到手机"),
|
||||
dense: true,
|
||||
hoverColor: Colors.transparent,
|
||||
focusColor: Colors.transparent,
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () async {
|
||||
mobileCer(await localIp());
|
||||
@@ -124,6 +130,7 @@ class _SwitchState extends State<_Switch> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
hoverColor: Colors.transparent,
|
||||
title: const Text("启用Https代理", style: TextStyle(fontSize: 12)),
|
||||
visualDensity: const VisualDensity(horizontal: -4),
|
||||
dense: true,
|
||||
|
||||
@@ -11,9 +11,9 @@ import 'launch/launch.dart';
|
||||
|
||||
class Toolbar extends StatefulWidget {
|
||||
final ProxyServer proxyServer;
|
||||
final DomainWidget domainWidget;
|
||||
final GlobalKey<DomainWidgetState> domainStateKey;
|
||||
|
||||
const Toolbar(this.proxyServer, this.domainWidget, {super.key});
|
||||
const Toolbar(this.proxyServer, this.domainStateKey, {super.key});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
@@ -33,7 +33,7 @@ class _ToolbarState extends State<Toolbar> with WindowListener {
|
||||
tooltip: "清理",
|
||||
icon: const Icon(Icons.cleaning_services_outlined),
|
||||
onPressed: () {
|
||||
widget.domainWidget.clean();
|
||||
widget.domainStateKey.currentState?.clean();
|
||||
}),
|
||||
const Padding(padding: EdgeInsets.only(left: 30)),
|
||||
SslWidget(proxyServer: widget.proxyServer),
|
||||
|
||||
@@ -15,3 +15,7 @@ Future<String> localIp() async {
|
||||
String ip = await NetworkInterface.list().then((interfaces) => interfaces.first.addresses.first.address);
|
||||
return ip;
|
||||
}
|
||||
|
||||
Future<String> networkName() {
|
||||
return NetworkInterface.list().then((interfaces) => interfaces.first.name);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user