feat: add system tray for desktop

This commit is contained in:
Prateek Sunal 2024-03-23 19:18:30 +05:30
parent 5aec3bc7fd
commit 19c2e50ef2
16 changed files with 83 additions and 4 deletions

View file

@ -83,7 +83,7 @@ jobs:
- name: Install dependencies for desktop build - name: Install dependencies for desktop build
run: | run: |
sudo apt-get update -y sudo apt-get update -y
sudo apt-get install -y libsecret-1-dev libsodium-dev libwebkit2gtk-4.0-dev libfuse2 ninja-build libgtk-3-dev dpkg-dev pkg-config rpm libsqlite3-dev locate sudo apt-get install -y libsecret-1-dev libsodium-dev libwebkit2gtk-4.0-dev libfuse2 ninja-build libgtk-3-dev dpkg-dev pkg-config rpm libsqlite3-dev locate appindicator3-0.1 libappindicator3-dev
- name: Install appimagetool - name: Install appimagetool
run: | run: |

BIN
auth/assets/icon-light.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -18,6 +18,7 @@ import 'package:ente_auth/ui/settings/app_update_dialog.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:system_tray/system_tray.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
class App extends StatefulWidget { class App extends StatefulWidget {
@ -43,9 +44,14 @@ class _AppState extends State<App> with WindowListener {
}); });
} }
Future<void> initWindowManager() async {
windowManager.addListener(this);
await windowManager.setPreventClose(true);
}
@override @override
void initState() { void initState() {
windowManager.addListener(this); initWindowManager();
_signedOutEvent = Bus.instance.on<SignedOutEvent>().listen((event) { _signedOutEvent = Bus.instance.on<SignedOutEvent>().listen((event) {
if (mounted) { if (mounted) {
setState(() {}); setState(() {});
@ -139,6 +145,12 @@ class _AppState extends State<App> with WindowListener {
}; };
} }
@override
void onWindowClose() async {
final AppWindow appWindow = AppWindow();
await appWindow.hide();
}
@override @override
void onWindowResize() { void onWindowResize() {
WindowListenerService.instance.onWindowResize().ignore(); WindowListenerService.instance.onWindowResize().ignore();

View file

@ -31,13 +31,50 @@ import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:privacy_screen/privacy_screen.dart'; import 'package:privacy_screen/privacy_screen.dart';
import 'package:system_tray/system_tray.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
final _logger = Logger("main"); final _logger = Logger("main");
Future<void> initSystemTray() async {
String path =
Platform.isWindows ? 'assets/icon-light.ico' : 'assets/icon-light.png';
final AppWindow appWindow = AppWindow();
final SystemTray systemTray = SystemTray();
// We first init the systray menu
await systemTray.initSystemTray(
title: "",
iconPath: path,
);
// create context menu
final show = MenuItem(label: 'Show', onClicked: () => appWindow.show());
final hide = MenuItem(label: 'Hide', onClicked: () => appWindow.hide());
final exit = MenuItem(label: 'Exit', onClicked: () => appWindow.close());
// set context menu
await systemTray.setContextMenu([show, hide, exit]);
const kSystemTrayEventClick = 'leftMouseDown';
const kSystemTrayEventRightClick = 'rightMouseDown';
// // handle system tray event
systemTray.registerSystemTrayEventHandler((eventName) {
debugPrint("eventName: $eventName");
if (eventName == kSystemTrayEventClick) {
Platform.isWindows ? appWindow.show() : systemTray.popUpContextMenu();
} else if (eventName == kSystemTrayEventRightClick) {
Platform.isWindows ? systemTray.popUpContextMenu() : appWindow.show();
}
});
}
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
initSystemTray().ignore();
if (PlatformUtil.isDesktop()) { if (PlatformUtil.isDesktop()) {
await windowManager.ensureInitialized(); await windowManager.ensureInitialized();
await WindowListenerService.instance.init(); await WindowListenerService.instance.init();

View file

@ -16,6 +16,7 @@
#include <smart_auth/smart_auth_plugin.h> #include <smart_auth/smart_auth_plugin.h>
#include <sodium_libs/sodium_libs_plugin.h> #include <sodium_libs/sodium_libs_plugin.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
#include <system_tray/system_tray_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
#include <window_manager/window_manager_plugin.h> #include <window_manager/window_manager_plugin.h>
@ -50,6 +51,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_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) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View file

@ -13,6 +13,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
smart_auth smart_auth
sodium_libs sodium_libs
sqlite3_flutter_libs sqlite3_flutter_libs
system_tray
url_launcher_linux url_launcher_linux
window_manager window_manager
) )

View file

@ -7,7 +7,7 @@ keywords:
- Authentication - Authentication
- 2FA - 2FA
generic_name: Ente Authentication generic_name: ente Auth
categories: categories:
- Utility - Utility

View file

@ -15,6 +15,9 @@ dependencies:
- libsqlite3-0 - libsqlite3-0
- libsodium23 - libsodium23
- libsecret-1-0 - libsecret-1-0
- libappindicator3-1 | libayatana-appindicator3-1
- gir1.2-appindicator3-0.1 | gir1.2-ayatanaappindicator3-0.1
- libayatana-ido3-0.4-0
keywords: keywords:
- Authentication - Authentication

View file

@ -14,6 +14,7 @@ dependencies:
- webkit2gtk-4.0 - webkit2gtk-4.0
- libsodium - libsodium
- libsecret - libsecret
- libappindicator
keywords: keywords:
- Authentication - Authentication

View file

@ -24,6 +24,7 @@ import smart_auth
import sodium_libs import sodium_libs
import sqflite import sqflite
import sqlite3_flutter_libs import sqlite3_flutter_libs
import system_tray
import url_launcher_macos import url_launcher_macos
import window_manager import window_manager
@ -47,6 +48,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SodiumLibsPlugin.register(with: registry.registrar(forPlugin: "SodiumLibsPlugin")) SodiumLibsPlugin.register(with: registry.registrar(forPlugin: "SodiumLibsPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
SystemTrayPlugin.register(with: registry.registrar(forPlugin: "SystemTrayPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
} }

View file

@ -63,6 +63,8 @@ PODS:
- sqlite3/fts5 - sqlite3/fts5
- sqlite3/perf-threadsafe - sqlite3/perf-threadsafe
- sqlite3/rtree - sqlite3/rtree
- system_tray (0.0.1):
- FlutterMacOS
- url_launcher_macos (0.0.1): - url_launcher_macos (0.0.1):
- FlutterMacOS - FlutterMacOS
- window_manager (0.2.0): - window_manager (0.2.0):
@ -89,6 +91,7 @@ DEPENDENCIES:
- sodium_libs (from `Flutter/ephemeral/.symlinks/plugins/sodium_libs/macos`) - sodium_libs (from `Flutter/ephemeral/.symlinks/plugins/sodium_libs/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`)
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`) - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`)
- system_tray (from `Flutter/ephemeral/.symlinks/plugins/system_tray/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
@ -141,6 +144,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin :path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin
sqlite3_flutter_libs: sqlite3_flutter_libs:
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos
system_tray:
:path: Flutter/ephemeral/.symlinks/plugins/system_tray/macos
url_launcher_macos: url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
window_manager: window_manager:
@ -172,6 +177,7 @@ SPEC CHECKSUMS:
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
sqlite3: 73b7fc691fdc43277614250e04d183740cb15078 sqlite3: 73b7fc691fdc43277614250e04d183740cb15078
sqlite3_flutter_libs: 06a05802529659a272beac4ee1350bfec294f386 sqlite3_flutter_libs: 06a05802529659a272beac4ee1350bfec294f386
system_tray: e53c972838c69589ff2e77d6d3abfd71332f9e5d
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8

View file

@ -4,6 +4,6 @@ import FlutterMacOS
@NSApplicationMain @NSApplicationMain
class AppDelegate: FlutterAppDelegate { class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true return false
} }
} }

View file

@ -1463,6 +1463,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0+1" version: "3.1.0+1"
system_tray:
dependency: "direct main"
description:
name: system_tray
sha256: "1bcc11bc230033be20d7443c29f65f68d67169715a838a1122f20fbff5dd2d19"
url: "https://pub.dev"
source: hosted
version: "0.1.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:

View file

@ -93,6 +93,7 @@ dependencies:
sqlite3_flutter_libs: ^0.5.19+1 sqlite3_flutter_libs: ^0.5.19+1
step_progress_indicator: ^1.0.2 step_progress_indicator: ^1.0.2
styled_text: ^8.1.0 styled_text: ^8.1.0
system_tray: ^0.1.1
tuple: ^2.0.0 tuple: ^2.0.0
url_launcher: ^6.1.5 url_launcher: ^6.1.5
uuid: ^4.2.2 uuid: ^4.2.2

View file

@ -19,6 +19,7 @@
#include <smart_auth/smart_auth_plugin.h> #include <smart_auth/smart_auth_plugin.h>
#include <sodium_libs/sodium_libs_plugin_c_api.h> #include <sodium_libs/sodium_libs_plugin_c_api.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
#include <system_tray/system_tray_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
#include <window_manager/window_manager_plugin.h> #include <window_manager/window_manager_plugin.h>
@ -49,6 +50,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("SodiumLibsPluginCApi")); registry->GetRegistrarForPlugin("SodiumLibsPluginCApi"));
Sqlite3FlutterLibsPluginRegisterWithRegistrar( Sqlite3FlutterLibsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin")); registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
SystemTrayPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SystemTrayPlugin"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows")); registry->GetRegistrarForPlugin("UrlLauncherWindows"));
WindowManagerPluginRegisterWithRegistrar( WindowManagerPluginRegisterWithRegistrar(

View file

@ -16,6 +16,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
smart_auth smart_auth
sodium_libs sodium_libs
sqlite3_flutter_libs sqlite3_flutter_libs
system_tray
url_launcher_windows url_launcher_windows
window_manager window_manager
) )