From 193e842766029a56ebd7e045f09a9ffddddd585d Mon Sep 17 00:00:00 2001 From: atavism Date: Fri, 24 May 2024 06:49:50 -0700 Subject: [PATCH] System tray updates for Windows (#1086) * update flutter version * Update window_manager and tray_manager * try calling setupMenu prior to addListener * setupMenu after initializing window manager * Add TrayHandler * Add TrayHandler * revert pubspec.yaml changes * update flutter version * Additional clean-ups * code review updates --- lib/common/common_desktop.dart | 51 +----------------- lib/common/tray_handler.dart | 97 ++++++++++++++++++++++++++++++++++ lib/home.dart | 36 +------------ lib/vpn/vpn_switch.dart | 4 +- pubspec.lock | 8 +-- 5 files changed, 106 insertions(+), 90 deletions(-) create mode 100644 lib/common/tray_handler.dart diff --git a/lib/common/common_desktop.dart b/lib/common/common_desktop.dart index 8c3388445..e8c95fad7 100644 --- a/lib/common/common_desktop.dart +++ b/lib/common/common_desktop.dart @@ -12,56 +12,7 @@ export 'dart:ffi'; // For FFI export 'package:ffi/ffi.dart'; export 'package:ffi/src/utf8.dart'; export 'package:lantern/ffi.dart'; +export 'package:lantern/common/tray_handler.dart'; export 'package:lantern/common/ui/websocket.dart'; export 'package:web_socket_channel/io.dart'; export 'package:web_socket_channel/web_socket_channel.dart'; - -// Include resources here just for desktop compatibility or use - -String systemTrayIcon(bool connected) { - if (connected) { - return Platform.isWindows - ? 'assets/images/lantern_connected_32.ico' - : 'assets/images/lantern_connected_32.png'; - } - return Platform.isWindows - ? 'assets/images/lantern_disconnected_32.ico' - : 'assets/images/lantern_disconnected_32.png'; -} - -// void setSelectedTab(BuildContext context, String name) { -// final tab = name.toNativeUtf8(); -// final currentTab = ffiSelectedTab().toDartString(); -// setSelectTab(tab); -// // when the user clicks on the active tab again, do nothing -// if (currentTab == name) return; -// // context.pushRoute(Home()); -// } - -Future setupMenu(bool isConnected) async { - Menu menu = Menu( - items: [ - MenuItem( - key: 'status', - disabled: true, - label: isConnected ? 'status_on'.i18n : 'status_off'.i18n, - ), - MenuItem( - key: 'status', - label: isConnected ? 'disconnect'.i18n : 'connect'.i18n, - ), - MenuItem.separator(), - MenuItem( - key: 'show_window', - label: 'show'.i18n, - ), - MenuItem.separator(), - MenuItem( - key: 'exit', - label: 'exit'.i18n, - ), - ], - ); - await trayManager.setContextMenu(menu); - await trayManager.setIcon(systemTrayIcon(isConnected)); -} diff --git a/lib/common/tray_handler.dart b/lib/common/tray_handler.dart new file mode 100644 index 000000000..19d8b68dd --- /dev/null +++ b/lib/common/tray_handler.dart @@ -0,0 +1,97 @@ +import 'dart:ui'; + +import 'package:lantern/common/common.dart'; +import 'package:lantern/common/common_desktop.dart'; +import 'package:tray_manager/tray_manager.dart'; +import 'package:window_manager/window_manager.dart'; + +String systemTrayIcon(bool connected) { + if (connected) { + return Platform.isWindows + ? 'assets/images/lantern_connected_32.ico' + : 'assets/images/lantern_connected_32.png'; + } + return Platform.isWindows + ? 'assets/images/lantern_disconnected_32.ico' + : 'assets/images/lantern_disconnected_32.png'; +} + + +class TrayHandler with TrayListener { + factory TrayHandler() => _getInstance(); + + static TrayHandler get instance => _getInstance(); + static TrayHandler? _instance; + + static TrayHandler _getInstance() { + _instance ??= TrayHandler._internal(); + return _instance!; + } + + TrayHandler._internal() { + if (isDesktop()) { + setupTray(false); + } + } + + Future setupTray(bool isConnected) async { + await trayManager.setIcon(systemTrayIcon(isConnected)); + Menu menu = Menu( + items: [ + MenuItem( + key: 'status', + disabled: true, + label: isConnected ? 'status_on'.i18n : 'status_off'.i18n, + ), + MenuItem( + key: 'status', + label: isConnected ? 'disconnect'.i18n : 'connect'.i18n, + ), + MenuItem.separator(), + MenuItem( + key: 'show_window', + label: 'show'.i18n, + ), + MenuItem.separator(), + MenuItem( + key: 'exit', + label: 'exit'.i18n, + ), + ], + ); + await trayManager.setContextMenu(menu); + } + + @override + void onTrayMenuItemClick(MenuItem menuItem) { + switch (menuItem.key) { + case 'show': + windowManager.focus(); + windowManager.setSkipTaskbar(false); + case 'exit': + windowManager.destroy(); + ffiExit(); + case 'status': + final status = ffiVpnStatus().toDartString(); + bool isConnected = status == "connected"; + if (isConnected) { + sysProxyOff(); + setupTray(false); + } else { + sysProxyOn(); + setupTray(true); + } + } + } + + @override + Future onTrayIconMouseDown() async { + windowManager.show(); + trayManager.popUpContextMenu(); + } + + @override + void onTrayIconRightMouseDown() { + trayManager.popUpContextMenu(); + } +} \ No newline at end of file diff --git a/lib/home.dart b/lib/home.dart index 930b837e0..c99dd2568 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -97,39 +97,7 @@ class _HomePageState extends State with TrayListener, WindowListener { } void setupTrayManager() async { - trayManager.addListener(this); - await setupMenu(false); - } - - @override - void onTrayIconMouseDown() { - windowManager.show(); - trayManager.popUpContextMenu(); - } - - @override - void onTrayIconRightMouseDown() { - trayManager.popUpContextMenu(); - } - - @override - void onTrayMenuItemClick(MenuItem menuItem) async { - switch (menuItem.key) { - case 'show': - windowManager.focus(); - case 'exit': - ffiExit(); - case 'status': - final status = ffiVpnStatus().toDartString(); - bool isConnected = status == "connected"; - if (isConnected) { - sysProxyOff(); - await setupMenu(false); - } else { - sysProxyOn(); - await setupMenu(true); - } - } + trayManager.addListener(TrayHandler.instance); } @override @@ -181,7 +149,7 @@ class _HomePageState extends State with TrayListener, WindowListener { @override void dispose() { if (isDesktop()) { - trayManager.removeListener(this); + trayManager.removeListener(TrayHandler.instance); windowManager.removeListener(this); } if (_cancelEventSubscription != null) { diff --git a/lib/vpn/vpn_switch.dart b/lib/vpn/vpn_switch.dart index 3df9fc576..88728e3b9 100644 --- a/lib/vpn/vpn_switch.dart +++ b/lib/vpn/vpn_switch.dart @@ -21,10 +21,10 @@ class _VPNSwitchState extends State { bool isConnected = vpnStatus == 'connected'; if (isConnected) { sysProxyOff(); - await setupMenu(false); + await TrayHandler.instance.setupTray(false); } else { sysProxyOn(); - await setupMenu(true); + await TrayHandler.instance.setupTray(true); } } diff --git a/pubspec.lock b/pubspec.lock index 06ae014b4..a4c37715c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1670,10 +1670,10 @@ packages: dependency: "direct main" description: name: tray_manager - sha256: e0ac9a88b2700f366b8629b97e8663b6ef450a2f169560a685dc167bfe9c9c29 + sha256: c9a63fd88bd3546287a7eb8ccc978d707eef82c775397af17dda3a4f4c039e64 url: "https://pub.dev" source: hosted - version: "0.2.2" + version: "0.2.3" typed_data: dependency: transitive description: @@ -1982,10 +1982,10 @@ packages: dependency: "direct main" description: name: window_manager - sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 + sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf" url: "https://pub.dev" source: hosted - version: "0.3.8" + version: "0.3.9" xdg_directories: dependency: transitive description: