import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:kaer_with_panels/app/localization/kr_language_utils.dart'; import 'package:kaer_with_panels/app/utils/kr_log_util.dart'; import 'package:kaer_with_panels/singbox/model/singbox_status.dart'; import 'package:kaer_with_panels/app/localization/app_translations.dart'; import 'package:window_manager/window_manager.dart'; import 'package:tray_manager/tray_manager.dart'; import 'dart:io' show Platform; import '../services/singbox_imp/kr_sing_box_imp.dart'; class KRWindowManager with WindowListener, TrayListener { static final KRWindowManager _instance = KRWindowManager._internal(); factory KRWindowManager() => _instance; KRWindowManager._internal(); /// 初始化窗口管理器 Future kr_initWindowManager() async { KRLogUtil.kr_i('kr_initWindowManager: 开始初始化窗口管理器'); await windowManager.ensureInitialized(); KRLogUtil.kr_i('kr_initWindowManager: 窗口管理器已初始化'); const WindowOptions windowOptions = WindowOptions( size: Size(800, 668), minimumSize: Size(800, 668), center: true, backgroundColor: Colors.white, skipTaskbar: false, title: 'Hi快VPN', titleBarStyle: TitleBarStyle.normal, windowButtonVisibility: true, ); await windowManager.waitUntilReadyToShow(windowOptions); KRLogUtil.kr_i('kr_initWindowManager: 窗口准备就绪'); // 先添加监听器 windowManager.addListener(this); KRLogUtil.kr_i('kr_initWindowManager: 已添加窗口监听器'); // 确保在 Windows 下正确设置窗口属性 if (Platform.isWindows) { await windowManager.setTitleBarStyle(TitleBarStyle.normal); await windowManager.setTitle('HiFastVPN'); await windowManager.setSize(const Size(800, 668)); await windowManager.setMinimumSize(const Size(800, 668)); await windowManager.center(); await windowManager.show(); // 阻止窗口关闭 await windowManager.setPreventClose(true); } else { await windowManager.setTitle('Kaer VPN'); await windowManager.setSize(const Size(800, 668)); await windowManager.setMinimumSize(const Size(800, 668)); await windowManager.center(); } // 初始化托盘 await _initTray(); // 初始化平台通道 _initPlatformChannel(); KRLogUtil.kr_i('kr_initWindowManager: 初始化完成'); ever(KRLanguageUtils.kr_language, (_) { final Menu menu = Menu( items: [ MenuItem( label: AppTranslations.kr_tray.openDashboard, onClick: (_) => _showWindow(), ), if (Platform.isMacOS) MenuItem.separator(), if (Platform.isMacOS) MenuItem( label: AppTranslations.kr_tray.copyToTerminal, onClick: (_) => _copyToTerminal(), ), MenuItem.separator(), MenuItem( label: AppTranslations.kr_tray.exitApp, onClick: (_) => _exitApp(), ), ], ); trayManager.setContextMenu(menu); }); } /// 初始化平台通道 void _initPlatformChannel() { if (Platform.isMacOS) { const platform = MethodChannel('kaer_vpn/terminate'); platform.setMethodCallHandler((call) async { if (call.method == 'onTerminate') { KRLogUtil.kr_i('收到应用终止通知'); await _handleTerminate(); } }); } } /// 初始化托盘 Future _initTray() async { KRLogUtil.kr_i('_initTray: 开始初始化托盘'); trayManager.addListener(this); final String iconPath = Platform.isMacOS ? 'assets/images/tray_icon.png' : 'assets/images/tray_icon.ico'; await trayManager.setIcon(iconPath); // 初始化托盘 Future.delayed(const Duration(seconds: 1), () async { final Menu menu = Menu( items: [ MenuItem( label: AppTranslations.kr_tray.openDashboard, onClick: (_) => _showWindow(), ), if (Platform.isMacOS) MenuItem.separator(), if (Platform.isMacOS) MenuItem( label: AppTranslations.kr_tray.copyToTerminal, onClick: (_) => _copyToTerminal(), ), MenuItem.separator(), MenuItem( label: AppTranslations.kr_tray.exitApp, onClick: (_) => _exitApp(), ), ], ); await trayManager.setContextMenu(menu); }); } /// 复制到终端 Future _copyToTerminal() async { final String kr_port = KRSingBoxImp.instance.kr_port.toString(); final String proxyText = 'export https_proxy=http://127.0.0.1:$kr_port http_proxy=http://127.0.0.1:$kr_port all_proxy=socks5://127.0.0.1:$kr_port'; await Clipboard.setData(ClipboardData(text: proxyText)); } /// 退出应用 Future _exitApp() async { KRLogUtil.kr_i('_exitApp: 退出应用'); await _handleTerminate(); await windowManager.destroy(); } /// 显示窗口 Future _showWindow() async { KRLogUtil.kr_i('_showWindow: 开始显示窗口'); try { await windowManager.show(); await windowManager.focus(); await windowManager.setSkipTaskbar(false); await windowManager.setAlwaysOnTop(true); await Future.delayed(const Duration(milliseconds: 100)); await windowManager.setAlwaysOnTop(false); KRLogUtil.kr_i('_showWindow: 窗口显示成功'); } catch (e) { KRLogUtil.kr_e('_showWindow: 显示窗口失败 - $e'); } } @override void onWindowEvent(String eventName) { KRLogUtil.kr_i('onWindowEvent: 收到窗口事件 - $eventName'); // 移除 Windows 下自动显示窗口的逻辑 } @override void onWindowClose() async { if (Platform.isWindows) { await windowManager.hide(); } else if (Platform.isMacOS) { await windowManager.hide(); } } @override void onTrayIconMouseDown() { // 左键点击只显示菜单 trayManager.popUpContextMenu(); } @override void onTrayIconRightMouseDown() { // 右键点击只显示菜单 trayManager.popUpContextMenu(); } @override void onWindowFocus() { // 移除自动显示窗口的逻辑 } @override void onWindowBlur() { // 当窗口失去焦点时,保持窗口可见 } /// 设置窗口背景颜色 Future kr_setBackgroundColor(Color color) async { await windowManager.setBackgroundColor(color); } /// 处理应用终止 Future _handleTerminate() async { KRLogUtil.kr_i('_handleTerminate: 处理应用终止'); if (KRSingBoxImp.instance.kr_status == SingboxStatus.started()) { await KRSingBoxImp.instance.kr_stop(); } await trayManager.destroy(); } }