// system_tray.dart — 桌面端系统托盘 + 关闭即最小化到托盘。 // // macOS/Windows/Linux:关闭主窗口不退出,而是隐藏到托盘;托盘图标点击/菜单 // 可重新显示或真正退出。移动端/web 不涉及。 import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:tray_manager/tray_manager.dart'; import 'package:window_manager/window_manager.dart'; bool get isDesktop => !kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux); class TrayService with TrayListener, WindowListener { TrayService._(); static final TrayService instance = TrayService._(); /// 在 runApp 前调用(仅桌面端)。设置窗口拦截关闭 + 托盘图标与菜单。 Future init() async { await windowManager.ensureInitialized(); // 关闭窗口转为隐藏到托盘(见 onWindowClose)。 await windowManager.setPreventClose(true); windowManager.addListener(this); trayManager.addListener(this); await trayManager.setIcon('assets/tray_icon.png'); await trayManager.setToolTip('穿山甲 Pangolin'); await trayManager.setContextMenu(Menu(items: [ MenuItem(key: 'show', label: '显示主界面'), MenuItem.separator(), MenuItem(key: 'quit', label: '退出'), ])); } Future _show() async { await windowManager.show(); await windowManager.focus(); } // ── 托盘事件 ────────────────────────────────────────────────── @override void onTrayIconMouseDown() => _show(); @override void onTrayIconRightMouseDown() => trayManager.popUpContextMenu(); @override void onTrayMenuItemClick(MenuItem menuItem) { switch (menuItem.key) { case 'show': _show(); case 'quit': windowManager.setPreventClose(false); windowManager.destroy(); } } // ── 窗口事件 ────────────────────────────────────────────────── @override void onWindowClose() async { // 点关闭 → 隐藏到托盘而非退出(常驻保持隧道)。 if (await windowManager.isPreventClose()) { await windowManager.hide(); } } }