import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:shortid/shortid.dart'; import 'package:path/path.dart' as path; import '../../constants/assets.dart'; import 'menu_base/menu_base.dart'; import 'tray_listener.dart'; const kEventOnTrayIconLButtonDown = 'onTrayIconLButtonDown'; const kEventOnTrayIconLButtonUp = 'onTrayIconLButtonUp'; const kEventOnTrayIconRButtonDown = 'onTrayIconRButtonDown'; const kEventOnTrayIconRButtonUp = 'onTrayIconRButtonUp'; const kEventOnTrayMenuItemClick = 'onTrayMenuItemClick'; class TrayController { final _channel = const MethodChannel("app.nomo/tray"); final ObserverList _listeners = ObserverList(); Menu? _trayMenu; TrayController() { _channel.setMethodCallHandler(_methodCallHandler); } Future _methodCallHandler(MethodCall call) async { for (final TrayListener listener in _listeners) { switch (call.method) { case kEventOnTrayIconLButtonDown: listener.onTrayIconLButtonDown(); break; case kEventOnTrayIconLButtonUp: listener.onTrayIconLButtonUp(); break; case kEventOnTrayIconRButtonDown: listener.onTrayIconRButtonDown(); break; case kEventOnTrayIconRButtonUp: listener.onTrayIconRButtonUp(); break; case kEventOnTrayMenuItemClick: int id = call.arguments['id']; MenuItem? menuItem = _trayMenu?.getMenuItemById(id); if (menuItem != null) { bool? oldChecked = menuItem.checked; if (menuItem.onClick != null) { menuItem.onClick!(menuItem); } listener.onTrayMenuItemClick(menuItem); bool? newChecked = menuItem.checked; if (oldChecked != newChecked) { await _setContextMenu(_trayMenu!); } } break; } } } Future _setContextMenu(Menu menu) { _trayMenu = menu; final Map arguments = {'menu': menu.toJson()}; return _channel.invokeMethod('setContextMenu', arguments); } Future _setSystemTrayWindows(String iconPath, String? tooltip) { final Map arguments = { 'id': shortid.generate(), 'icon': path.joinAll([ path.dirname(Platform.resolvedExecutable), 'data/flutter_assets', iconPath, ]), 'tooltip': tooltip ?? '', }; return _channel.invokeMethod('setSystemTray', arguments); } /// 设置托盘图标 Future setSystemTray( bool isConnected, bool isDark, { String? title, String? tooltip, }) { String iconPath; if (isConnected) { iconPath = isDark ? Assets.trayIconDarkConnectedWin : Assets.trayIconLightConnectedWin; } else { iconPath = isDark ? Assets.trayIconDarkUnConnectedWin : Assets.trayIconLightUnConnectedWin; } if (Platform.isWindows) { return _setSystemTrayWindows(iconPath, tooltip); } else { throw UnimplementedError(); } } /// 设置托盘菜单 Future setContextMenu(Menu trayMenu) { return _setContextMenu(trayMenu); } /// 弹出系统托盘菜单 Future popUpContextMenu() { return _channel.invokeMethod('popupContextMenu'); } /// 销毁系统托盘 Future resetSystemTray() { return _channel.invokeMethod('resetSystemTray'); } bool get hasListeners { return _listeners.isNotEmpty; } void addListener(TrayListener listener) { _listeners.add(listener); } void removeListener(TrayListener listener) { _listeners.remove(listener); } }