windows toolbar

This commit is contained in:
wanghongenpin
2025-08-18 19:14:09 +08:00
parent 9368391cef
commit 2d76fb1b5c
19 changed files with 159 additions and 66 deletions

View File

@@ -51,7 +51,7 @@ android {
applicationId "com.network.proxy"
ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64' }
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 21
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
multiDexEnabled true
versionCode flutterVersionCode.toInteger()
@@ -88,4 +88,4 @@ flutter {
}
dependencies {
}
}

BIN
assets/icon_foreground.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -64,7 +64,7 @@ void main(List<String> args) async {
minimumSize: const Size(1000, 600),
size: windowSize,
center: true,
titleBarStyle: Platform.isMacOS ? TitleBarStyle.hidden : TitleBarStyle.normal);
titleBarStyle: TitleBarStyle.hidden );
Offset? windowPosition = appConfiguration.windowPosition;

View File

@@ -170,9 +170,9 @@ class Channel {
await Future.delayed(const Duration(milliseconds: 150));
}
isOpen = false;
if (!isWriting) {
await _socket.flush();
}
// if (!isWriting) {
// await _socket.flush();
// }
await _socket.close();
_socket.destroy();
}

View File

@@ -208,7 +208,7 @@ class Server extends Network {
Channel? remoteChannel = channelContext.serverChannel;
if (HostFilter.filter(hostAndPort.host) || !configuration.enableSsl) {
if (!isHttp || HostFilter.filter(hostAndPort.host) || !configuration.enableSsl) {
remoteChannel = remoteChannel ?? await channelContext.connectServerChannel(hostAndPort, RelayHandler(channel));
relay(channel, remoteChannel);
channel.dispatcher.channelRead(channelContext, channel, data);

View File

@@ -19,9 +19,10 @@ import 'package:get/get.dart';
import 'package:proxypin/l10n/app_localizations.dart';
import 'package:proxypin/network/http/content_type.dart';
import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/utils/lang.dart';
import 'model/search_model.dart';
/// @author wanghongen
/// 2023/8/6
class SearchConditions extends StatefulWidget {

View File

@@ -14,6 +14,8 @@
* limitations under the License.
*/
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:proxypin/l10n/app_localizations.dart';
import 'package:proxypin/network/bin/configuration.dart';
@@ -32,6 +34,7 @@ import 'package:proxypin/ui/desktop/left_menus/history.dart';
import 'package:proxypin/ui/desktop/left_menus/navigation.dart';
import 'package:proxypin/ui/desktop/request/list.dart';
import 'package:proxypin/ui/desktop/toolbar/toolbar.dart';
import 'package:proxypin/ui/desktop/widgets/windows_toolbar.dart';
import 'package:proxypin/utils/listenable_list.dart';
import '../app_update/app_update_repository.dart';
@@ -111,9 +114,16 @@ class _DesktopHomePagePageState extends State<DesktopHomePage> implements EventL
return Scaffold(
appBar: Tab(
child: Container(
padding: EdgeInsets.only(bottom: 2.5),
margin: EdgeInsets.only(bottom: 2.5),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Theme.of(context).dividerColor.withOpacity(0.25), width: 0.2))),
child: Toolbar(proxyServer, requestListStateKey, sideNotifier: _selectIndex),
color: Theme.of(context).brightness == Brightness.dark ? null : Color(0xFFF9F9F9),
border: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor.withOpacity(0.3), width: Platform.isMacOS ? 0.2 : 0.55))),
child: Platform.isMacOS
? Toolbar(proxyServer, requestListStateKey)
: WindowsToolbar(title: Toolbar(proxyServer, requestListStateKey)),
)),
body: Row(
children: [

View File

@@ -33,11 +33,12 @@ import 'package:proxypin/network/http/http_client.dart';
import 'package:proxypin/ui/component/transition.dart';
import 'package:proxypin/ui/component/utils.dart';
import 'package:proxypin/ui/content/panel.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/ui/desktop/request/request.dart';
import 'package:proxypin/utils/keyword_highlight.dart';
import 'package:proxypin/utils/listenable_list.dart';
import '../../component/model/search_model.dart';
/// 左侧域名
/// @author wanghongen
/// 2023/10/8
@@ -78,7 +79,7 @@ class DomainWidgetState extends State<DomainList> with AutomaticKeepAliveClientM
bool sortDesc = true;
changeState() {
void changeState() {
if (!changing) {
changing = true;
Future.delayed(const Duration(milliseconds: 500), () {

View File

@@ -27,13 +27,13 @@ import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/network/http/http_client.dart';
import 'package:proxypin/ui/component/widgets.dart';
import 'package:proxypin/ui/content/panel.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/ui/desktop/request/request_sequence.dart';
import 'package:proxypin/ui/desktop/request/search.dart';
import 'package:proxypin/utils/har.dart';
import 'package:proxypin/utils/lang.dart';
import 'package:proxypin/utils/listenable_list.dart';
import '../../component/model/search_model.dart';
import 'domians.dart';
/// @author wanghongen

View File

@@ -21,11 +21,12 @@ import 'package:proxypin/network/bin/configuration.dart';
import 'package:proxypin/network/bin/server.dart';
import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/ui/component/utils.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/ui/desktop/request/request.dart';
import 'package:proxypin/utils/keyword_highlight.dart';
import 'package:proxypin/utils/listenable_list.dart';
import '../../component/model/search_model.dart';
///请求序列 列表
/// @author wanghongen
class RequestSequence extends StatefulWidget {

View File

@@ -16,8 +16,9 @@
import 'package:flutter/material.dart';
import 'package:proxypin/l10n/app_localizations.dart';
import 'package:proxypin/network/http/content_type.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/ui/desktop/request/search_condition.dart';
import 'package:proxypin/ui/component/search_condition.dart';
import '../../component/model/search_model.dart';
/// @author wanghongen
/// 2023/10/8

View File

@@ -33,9 +33,8 @@ import '../request/list.dart';
class Toolbar extends StatefulWidget {
final ProxyServer proxyServer;
final GlobalKey<DesktopRequestListState> requestListStateKey;
final ValueNotifier<int> sideNotifier;
const Toolbar(this.proxyServer, this.requestListStateKey, {super.key, required this.sideNotifier});
const Toolbar(this.proxyServer, this.requestListStateKey, {super.key});
@override
State<StatefulWidget> createState() {
@@ -53,7 +52,6 @@ class _ToolbarState extends State<Toolbar> {
}
bool onKeyEvent(KeyEvent event) {
if (HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.escape)) {
if (ModalRoute.of(context)?.isCurrent == false) {
Navigator.maybePop(context);
@@ -82,48 +80,34 @@ class _ToolbarState extends State<Toolbar> {
@override
Widget build(BuildContext context) {
return Row(
children: [
Padding(padding: EdgeInsets.only(left: Platform.isMacOS ? 80 : 30)),
SocketLaunch(proxyServer: widget.proxyServer, startup: widget.proxyServer.configuration.startup),
const Padding(padding: EdgeInsets.only(left: 18)),
IconButton(
tooltip: localizations.clear,
icon: const Icon(Icons.cleaning_services_outlined, size: 21),
onPressed: () {
widget.requestListStateKey.currentState?.clean();
}),
const Padding(padding: EdgeInsets.only(left: 18)),
SslWidget(proxyServer: widget.proxyServer), // SSL配置
const Padding(padding: EdgeInsets.only(left: 18)),
Setting(proxyServer: widget.proxyServer), // 设置
const Padding(padding: EdgeInsets.only(left: 18)),
IconButton(
tooltip: localizations.mobileConnect,
icon: const Icon(Icons.phone_iphone, size: 21),
onPressed: () async {
final ips = await localIps(readCache: false);
phoneConnect(ips, widget.proxyServer.port);
}),
const Expanded(child: SizedBox()), //自动扩展挤压
ValueListenableBuilder(
valueListenable: widget.sideNotifier,
builder: (_, sideIndex, __) => IconButton(
icon: Icon(Icons.space_dashboard, size: 20, color: sideIndex >= 0 ? Colors.blueGrey : Colors.grey),
onPressed: () {
if (widget.sideNotifier.value >= 0) {
widget.sideNotifier.value = -1;
} else {
widget.sideNotifier.value = 0;
}
},
)), //右对齐
const Padding(padding: EdgeInsets.only(left: 30)),
],
);
return Row(children: [
Padding(padding: EdgeInsets.only(left: Platform.isMacOS ? 80 : 20)),
SocketLaunch(proxyServer: widget.proxyServer, startup: widget.proxyServer.configuration.startup),
const Padding(padding: EdgeInsets.only(left: 18)),
IconButton(
tooltip: localizations.clear,
icon: const Icon(Icons.cleaning_services_outlined, size: 21),
onPressed: () {
widget.requestListStateKey.currentState?.clean();
}),
const Padding(padding: EdgeInsets.only(left: 18)),
SslWidget(proxyServer: widget.proxyServer), // SSL配置
const Padding(padding: EdgeInsets.only(left: 18)),
Setting(proxyServer: widget.proxyServer), // 设置
const Padding(padding: EdgeInsets.only(left: 18)),
IconButton(
tooltip: localizations.mobileConnect,
icon: const Icon(Icons.phone_iphone, size: 21),
onPressed: () async {
final ips = await localIps(readCache: false);
phoneConnect(ips, widget.proxyServer.port);
}),
const Padding(padding: EdgeInsets.only(left: 30)),
]);
}
phoneConnect(List<String> hosts, int port) {
void phoneConnect(List<String> hosts, int port) {
showDialog(
context: context,
builder: (context) {

View File

@@ -0,0 +1,91 @@
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
class WindowsToolbar extends StatefulWidget {
final Widget? title;
const WindowsToolbar({
super.key,
this.title,
});
@override
State<WindowsToolbar> createState() => _WindowsToolbarState();
}
class _WindowsToolbarState extends State<WindowsToolbar> with WindowListener {
@override
void initState() {
windowManager.addListener(this);
super.initState();
}
@override
void dispose() {
windowManager.removeListener(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
SizedBox(width: 7),
Padding(
padding: EdgeInsets.only(top: 2),
child: Center(
child: Image.asset(
'assets/icon_foreground.png',
width: 32,
))),
Expanded(
child: DragToMoveArea(
child: widget.title ?? Container(),
)),
WindowCaptionButton.minimize(
brightness: Theme.brightnessOf(context),
onPressed: () async {
bool isMinimized = await windowManager.isMinimized();
if (isMinimized) {
windowManager.restore();
} else {
windowManager.minimize();
}
}),
FutureBuilder<bool>(
future: windowManager.isMaximized(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.data == true) {
return WindowCaptionButton.unmaximize(
brightness: Theme.brightnessOf(context),
onPressed: () {
windowManager.unmaximize();
},
);
}
return WindowCaptionButton.maximize(
brightness: Theme.brightnessOf(context),
onPressed: () {
windowManager.maximize();
},
);
}),
WindowCaptionButton.close(
brightness: Theme.brightnessOf(context),
onPressed: () {
windowManager.close();
}),
],
);
}
@override
void onWindowMaximize() {
setState(() {});
}
@override
void onWindowUnmaximize() {
setState(() {});
}
}

View File

@@ -22,7 +22,6 @@ import 'package:proxypin/network/bin/server.dart';
import 'package:proxypin/network/channel/channel.dart';
import 'package:proxypin/network/channel/channel_context.dart';
import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/ui/mobile/request/domians.dart';
import 'package:proxypin/ui/mobile/request/request_sequence.dart';
import 'package:proxypin/utils/har.dart';
@@ -30,6 +29,8 @@ import 'package:proxypin/utils/listenable_list.dart';
import 'package:proxypin/utils/platform.dart';
import 'package:share_plus/share_plus.dart';
import '../../component/model/search_model.dart';
/// 请求列表
/// @author wanghongen
class RequestListWidget extends StatefulWidget {

View File

@@ -3,11 +3,12 @@ import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:proxypin/network/bin/server.dart';
import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/ui/mobile/request/request.dart';
import 'package:proxypin/utils/keyword_highlight.dart';
import 'package:proxypin/utils/listenable_list.dart';
import '../../component/model/search_model.dart';
///请求序列 列表
///@author wanghongen
class RequestSequence extends StatefulWidget {

View File

@@ -14,8 +14,9 @@
* limitations under the License.
*/
import 'package:flutter/material.dart';
import 'package:proxypin/ui/desktop/request/model/search_model.dart';
import 'package:proxypin/ui/desktop/request/search_condition.dart';
import 'package:proxypin/ui/component/search_condition.dart';
import '../../component/model/search_model.dart';
class MobileSearch extends StatefulWidget {
final Function(SearchModel searchModel)? onSearch;

View File

@@ -99,7 +99,7 @@ class _ToolboxState extends State<Toolbox> {
child: const Column(
children: [Icon(Icons.format_bold_outlined), SizedBox(height: 3), Text('Base64')]),
)),
const SizedBox(width: 15),
const SizedBox(width: 10),
InkWell(
onTap: () => encodeWindow(EncoderType.unicode, context),
child: Container(
@@ -107,7 +107,7 @@ class _ToolboxState extends State<Toolbox> {
child: const Column(
children: [Icon(Icons.format_underline_outlined), SizedBox(height: 3), Text('Unicode')]),
)),
const SizedBox(width: 15),
const SizedBox(width: 10),
InkWell(
onTap: () => encodeWindow(EncoderType.md5, context),
child: Container(
@@ -188,7 +188,7 @@ class _ToolboxState extends State<Toolbox> {
));
}
httpRequest() async {
Future<void> httpRequest() async {
if (Platforms.isMobile()) {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => MobileRequestEditor(proxyServer: widget.proxyServer)));

View File

@@ -64,4 +64,5 @@ flutter:
- assets/certs/ca.crt
- assets/certs/ca_key.pem
- assets/icon.png
- assets/icon_foreground.png
- assets/js/