diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index 6dfebbf..62ce433 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -610,7 +610,5 @@ }, "aiThinkingProcess": "AI Thinking Process", "accountSettingsApplied": "Account settings have been applied.", - "trayMenuShow": "Show Window", - "trayMenuHide": "Hide Window", "trayMenuExit": "Exit" } diff --git a/assets/translations/zh-CN.json b/assets/translations/zh-CN.json index 7f2d643..3303756 100644 --- a/assets/translations/zh-CN.json +++ b/assets/translations/zh-CN.json @@ -608,7 +608,5 @@ }, "aiThinkingProcess": "AI 思考过程", "accountSettingsApplied": "帐号设置已应用。", - "trayMenuShow": "显示窗口", - "trayMenuHide": "隐藏窗口", "trayMenuExit": "退出" } diff --git a/lib/main.dart b/lib/main.dart index fe07ad5..9bac356 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -42,10 +42,10 @@ import 'package:surface/types/chat.dart'; import 'package:surface/types/realm.dart'; import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy; import 'package:surface/widgets/dialog.dart'; +import 'package:tray_manager/tray_manager.dart'; import 'package:version/version.dart'; import 'package:workmanager/workmanager.dart'; import 'package:in_app_review/in_app_review.dart'; -import 'package:system_tray/system_tray.dart'; @pragma('vm:entry-point') void appBackgroundDispatcher() { @@ -209,7 +209,7 @@ class _AppSplashScreen extends StatefulWidget { State<_AppSplashScreen> createState() => _AppSplashScreenState(); } -class _AppSplashScreenState extends State<_AppSplashScreen> { +class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener { void _tryRequestRating() async { final prefs = await SharedPreferences.getInstance(); if (prefs.containsKey('first_boot_time')) { @@ -301,32 +301,26 @@ class _AppSplashScreenState extends State<_AppSplashScreen> { if (kIsWeb || Platform.isAndroid || Platform.isIOS) return; final icon = Platform.isWindows ? 'assets/icon/tray-icon.ico' : 'assets/icon/tray-icon.png'; - final SystemTray systemTray = SystemTray(); + final appVersion = await PackageInfo.fromPlatform(); - await systemTray.initSystemTray( - title: "", - iconPath: icon, + trayManager.addListener(this); + await trayManager.setIcon(icon); + + Menu menu = Menu( + items: [ + MenuItem( + key: 'version_label', + label: 'Solian ${appVersion.version}+${appVersion.buildNumber}', + disabled: true, + ), + MenuItem.separator(), + MenuItem( + key: 'exit', + label: 'trayMenuExit'.tr(), + ), + ], ); - - await systemTray.setContextMenu([ - MenuItem(label: 'trayMenuShow'.tr(), onClicked: () => appWindow.show()), - MenuItem(label: 'trayMenuHide'.tr(), onClicked: () => appWindow.hide()), - MenuItem( - label: 'trayMenuExit'.tr(), - onClicked: () { - _appLifecycleListener?.dispose(); - SystemChannels.platform.invokeMethod('SystemNavigator.pop'); - }, - ), - ]); - - systemTray.registerSystemTrayEventHandler((eventName) { - if (eventName == "leftMouseDown") { - Platform.isWindows ? appWindow.show() : systemTray.popUpContextMenu(); - } else if (eventName == "rightMouseDown") { - Platform.isWindows ? systemTray.popUpContextMenu() : appWindow.show(); - } - }); + await trayManager.setContextMenu(menu); } AppLifecycleListener? _appLifecycleListener; @@ -354,6 +348,40 @@ class _AppSplashScreenState extends State<_AppSplashScreen> { return AppExitResponse.cancel; } + @override + void onTrayIconMouseDown() { + if (Platform.isWindows) { + appWindow.show(); + } else { + trayManager.popUpContextMenu(); + } + } + + @override + void onTrayIconRightMouseDown() { + if (Platform.isWindows) { + trayManager.popUpContextMenu(); + } else { + appWindow.show(); + } + } + + @override + void onTrayMenuItemClick(MenuItem menuItem) { + switch (menuItem.key) { + case 'exit': + _appLifecycleListener?.dispose(); + SystemChannels.platform.invokeMethod('SystemNavigator.pop'); + break; + } + } + + @override + void dispose() { + if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) trayManager.removeListener(this); + super.dispose(); + } + @override Widget build(BuildContext context) { final cfg = context.read(); diff --git a/lib/providers/notification.dart b/lib/providers/notification.dart index 0604935..431900b 100644 --- a/lib/providers/notification.dart +++ b/lib/providers/notification.dart @@ -12,6 +12,7 @@ import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/userinfo.dart'; import 'package:surface/providers/websocket.dart'; import 'package:surface/types/notification.dart'; +import 'package:tray_manager/tray_manager.dart'; class NotificationProvider extends ChangeNotifier { late final SnNetworkProvider _sn; @@ -86,14 +87,26 @@ class NotificationProvider extends ChangeNotifier { notifyListeners(); }); notifyListeners(); + updateTray(); final doHaptic = _cfg.prefs.getBool(kAppNotifyWithHaptic) ?? true; if (doHaptic) HapticFeedback.mediumImpact(); } }); } + void updateTray() { + if (kIsWeb || Platform.isAndroid || Platform.isIOS) return; + if (notifications.isEmpty) { + trayManager.setTitle(''); + } else { + trayManager.setTitle(' ${notifications.length.toString()}'); + } + } + void clear() { showingCount = 0; + notifications.clear(); + updateTray(); notifyListeners(); } } diff --git a/lib/screens/notification.dart b/lib/screens/notification.dart index 64cb4e8..5536668 100644 --- a/lib/screens/notification.dart +++ b/lib/screens/notification.dart @@ -7,6 +7,7 @@ import 'package:material_symbols_icons/symbols.dart'; import 'package:provider/provider.dart'; import 'package:relative_time/relative_time.dart'; import 'package:styled_widget/styled_widget.dart'; +import 'package:surface/providers/notification.dart'; import 'package:surface/providers/sn_network.dart'; import 'package:surface/types/notification.dart'; import 'package:surface/types/post.dart'; @@ -54,6 +55,7 @@ class _NotificationScreenState extends State { try { final sn = context.read(); + final nty = context.read(); final resp = await sn.client.get('/cgi/id/notifications?take=10'); _totalCount = resp.data['count']; _notifications.addAll( @@ -62,6 +64,7 @@ class _NotificationScreenState extends State { .cast() ?? [], ); + nty.updateTray(); } catch (err) { if (!mounted) return; context.showErrorDialog(err); @@ -88,9 +91,11 @@ class _NotificationScreenState extends State { try { final sn = context.read(); + final nty = context.read(); final resp = await sn.client.put('/cgi/id/notifications/read/all'); _notifications.clear(); _fetchNotifications(); + nty.clear(); if (!mounted) return; context.showSnackbar( diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index eb4b81f..a611662 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { @@ -42,9 +42,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) pasteboard_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); pasteboard_plugin_register_with_registrar(pasteboard_registrar); - g_autoptr(FlPluginRegistrar) system_tray_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "SystemTrayPlugin"); - system_tray_plugin_register_with_registrar(system_tray_registrar); + g_autoptr(FlPluginRegistrar) tray_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin"); + tray_manager_plugin_register_with_registrar(tray_manager_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 56e525c..0fc5c17 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -11,7 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST media_kit_libs_linux media_kit_video pasteboard - system_tray + tray_manager url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 1552fc2..03e0386 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -29,7 +29,7 @@ import screen_brightness_macos import share_plus import shared_preferences_foundation import sqflite_darwin -import system_tray +import tray_manager import url_launcher_macos import video_compress import wakelock_plus @@ -59,7 +59,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) - SystemTrayPlugin.register(with: registry.registrar(forPlugin: "SystemTrayPlugin")) + TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 869d09d..3048cf7 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -174,7 +174,7 @@ PODS: - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - - system_tray (0.0.1): + - tray_manager (0.0.1): - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS @@ -212,7 +212,7 @@ DEPENDENCIES: - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`) - - system_tray (from `Flutter/ephemeral/.symlinks/plugins/system_tray/macos`) + - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - video_compress (from `Flutter/ephemeral/.symlinks/plugins/video_compress/macos`) - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) @@ -289,8 +289,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite_darwin: :path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin - system_tray: - :path: Flutter/ephemeral/.symlinks/plugins/system_tray/macos + tray_manager: + :path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos video_compress: @@ -339,7 +339,7 @@ SPEC CHECKSUMS: share_plus: 1fa619de8392a4398bfaf176d441853922614e89 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d - system_tray: e53c972838c69589ff2e77d6d3abfd71332f9e5d + tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 video_compress: c896234f100791b5fef7f049afa38f6d2ef7b42f wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 diff --git a/pubspec.lock b/pubspec.lock index 769ac83..2e08f53 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1282,6 +1282,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.5" + menu_base: + dependency: transitive + description: + name: menu_base + sha256: "820368014a171bd1241030278e6c2617354f492f5c703d7b7d4570a6b8b84405" + url: "https://pub.dev" + source: hosted + version: "0.1.1" meta: dependency: transitive description: @@ -1778,6 +1786,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + shortid: + dependency: transitive + description: + name: shortid + sha256: d0b40e3dbb50497dad107e19c54ca7de0d1a274eb9b4404991e443dadb9ebedb + url: "https://pub.dev" + source: hosted + version: "0.1.2" sky_engine: dependency: transitive description: flutter @@ -1927,14 +1943,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.0+3" - system_tray: - dependency: "direct main" - description: - name: system_tray - sha256: "1bcc11bc230033be20d7443c29f65f68d67169715a838a1122f20fbff5dd2d19" - url: "https://pub.dev" - source: hosted - version: "0.1.1" term_glyph: dependency: transitive description: @@ -1959,6 +1967,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + tray_manager: + dependency: "direct main" + description: + name: tray_manager + sha256: "80be6c508159a6f3c57983de795209ac13453e9832fd574143b06dceee188ed2" + url: "https://pub.dev" + source: hosted + version: "0.3.2" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 977d1ab..1610a52 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -118,7 +118,7 @@ dependencies: flutter_inappwebview: ^6.1.5 html: ^0.15.5 xml: ^6.5.0 - system_tray: ^0.1.1 + tray_manager: ^0.3.2 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 9054380..d668d1d 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { @@ -58,8 +58,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); SharePlusWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); - SystemTrayPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SystemTrayPlugin")); + TrayManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("TrayManagerPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index a12c723..47538d7 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -19,7 +19,7 @@ list(APPEND FLUTTER_PLUGIN_LIST permission_handler_windows screen_brightness_windows share_plus - system_tray + tray_manager url_launcher_windows )