Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System tray #22

Merged
merged 10 commits into from
May 19, 2023
15 changes: 13 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src-shared/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions src-tauri/src/commands/splash.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
use log::debug;
use tauri::Manager;

use crate::{commands::system_tray::SystemTrayManager, SYSTEMTRAY_MANAGER};

#[tauri::command]
pub async fn close_splashscreen(window: tauri::Window) {
debug!("[Core] Closing splash screen");
// Close splashscreen
if let Some(splashscreen) = window.get_window("splashscreen") {
splashscreen.close().unwrap();
}
// Show main window
window.get_window("main").unwrap().show().unwrap();

// Show the window if the "Start with system tray" config is set to false.
// Otherwise, keep the window hidden until the user clicks the system tray icon to show it.
let manager_guard = SYSTEMTRAY_MANAGER.lock().unwrap();
let manager: &SystemTrayManager = manager_guard.as_ref().unwrap();

if !manager.start_in_tray {
window.get_window("main").unwrap().show().unwrap();
}
}
83 changes: 83 additions & 0 deletions src-tauri/src/commands/system_tray.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use tauri::Manager;
use tauri::{
AppHandle, CustomMenuItem, Runtime, SystemTray, SystemTrayEvent, SystemTrayMenu,
};

use crate::SYSTEMTRAY_MANAGER;

const QUIT: &'static str = "quit";

#[derive(Debug, Clone)]
pub struct SystemTrayManager {
pub exit_in_tray: bool,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here I guess

Suggested change
pub exit_in_tray: bool,
pub close_to_tray: bool,

pub start_in_tray: bool,
}

impl SystemTrayManager {
pub fn new() -> SystemTrayManager {
SystemTrayManager { exit_in_tray: false, start_in_tray: false, }
}

// pub fn handle_window_exit<R: Runtime>(&self) -> impl Fn(GlobalWindowEvent<R>) + Send + Sync + 'static {
// return |event| match event.event() {
// tauri::WindowEvent::CloseRequested { api, .. } => {
// event.window().hide().unwrap();
// api.prevent_close();
// }
// _ => {}
// }
// }
Comment on lines +21 to +29
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's commented out, I assume this can be removed?

}

// Initializes the system tray with menus.
pub fn init_system_tray() -> SystemTray {
// Menus
let menu_quit = CustomMenuItem::new(QUIT, "Quit");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably find a way of localizing this as well, but I understand there's currently not yet a nice way of getting the translations to the rust side. I think doing that might be a bit outside of this PR's scope, especially when you consider the translations should change when the user switches language on the front, so that's probably something to look into after getting this merged.

tl;dr: this is fine as is, feel free to ignore. I've opened a separate issue for this in #23.


let tray_menu = SystemTrayMenu::new()
//.add_native_item(SystemTrayMenuItem::Separator)
.add_item(menu_quit);

let tray = SystemTray::new().with_menu(tray_menu);

return tray;
}

pub fn handle_events<R: Runtime>() -> impl Fn(&AppHandle<R>, SystemTrayEvent) + Send + Sync + 'static
{
return |app, event| {
let manager_guard = SYSTEMTRAY_MANAGER.lock().unwrap();
let manager = manager_guard.as_ref().unwrap();

match event {
SystemTrayEvent::MenuItemClick { id, .. } => {
match id.as_str() {
QUIT => std::process::exit(0),
_ => {}
}
},

// When clicking the tray icon, restore and focus window.
SystemTrayEvent::LeftClick { tray_id, .. } => {
let window = app.get_window("main").unwrap();
window.show().unwrap();
window.set_focus().unwrap();
}
_ => {}
};
}
}

#[tauri::command]
pub fn set_exit_in_system_tray(app_handle: AppHandle, status: bool) {
let mut manager_guard = SYSTEMTRAY_MANAGER.lock().unwrap();
let mut manager: &mut SystemTrayManager = manager_guard.as_mut().unwrap();
manager.exit_in_tray = status;
}

#[tauri::command]
pub fn set_start_in_system_tray(app_handle: AppHandle, status: bool) {
let mut manager_guard = SYSTEMTRAY_MANAGER.lock().unwrap();
let mut manager: &mut SystemTrayManager = manager_guard.as_mut().unwrap();
manager.start_in_tray = status;
}
61 changes: 32 additions & 29 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::commands::admin::start_elevation_sidecar;
use crate::image_cache::ImageCache;
use background::openvr::OpenVRManager;
use commands::log_utils::LOG_DIR;
use commands::system_tray::SystemTrayManager;
use cronjob::CronJob;
use log::{info, LevelFilter};
use oyasumi_shared::windows::is_elevated;
Expand All @@ -30,6 +31,7 @@ mod commands {
pub mod os;
pub mod osc;
pub mod splash;
pub mod system_tray;
}

mod background {
Expand All @@ -54,9 +56,11 @@ lazy_static! {
static ref SIDECAR_HTTP_SERVER_PORT: Mutex<Option<u16>> = Default::default();
static ref SIDECAR_PID: Mutex<Option<u32>> = Default::default();
static ref IMAGE_CACHE: Mutex<Option<ImageCache>> = Default::default();
static ref SYSTEMTRAY_MANAGER: Mutex<Option<SystemTrayManager>> = Default::default();
}

fn main() {

let app = tauri::Builder::default()
.plugin(tauri_plugin_store::Builder::default().build())
.plugin(tauri_plugin_fs_extra::init())
Expand Down Expand Up @@ -88,32 +92,6 @@ fn main() {
}
}
}))
// .on_window_event(|event| if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() {
// event.window().hide().unwrap();
// api.prevent_close();
// })
// .system_tray(
// SystemTray::new()
// )
// .on_system_tray_event(|app, event| match event {
// SystemTrayEvent::LeftClick {
// position: _,
// size: _,
// ..
// } => {
// let window = app.get_window("main").unwrap();
// window.show().unwrap();
// window.set_focus().unwrap();
// }
// SystemTrayEvent::RightClick {
// position: _,
// size: _,
// ..
// } => {
// // TODO: Implement context menu
// }
// _ => (),
// })
.setup(|app| {
// Set up window reference
let window = app.get_window("main").unwrap();
Expand All @@ -138,6 +116,10 @@ fn main() {
background::http_server::spawn_http_server_thread();
// Load sounds
commands::os::load_sounds();

// Initialize the system tray manager
let system_tray_manager = SystemTrayManager::new();
*SYSTEMTRAY_MANAGER.lock().unwrap() = Some(system_tray_manager);
});
// Reference log dir
{
Expand Down Expand Up @@ -191,13 +173,34 @@ fn main() {
commands::notifications::xsoverlay_send_message,
commands::image_cache::clean_image_cache,
commands::log_utils::clean_log_files,
]);
commands::system_tray::set_exit_in_system_tray,
commands::system_tray::set_start_in_system_tray,
])
.system_tray(commands::system_tray::init_system_tray())
.on_system_tray_event(commands::system_tray::handle_events())
.on_window_event(|event| match event.event() {
tauri::WindowEvent::CloseRequested { api, .. } => {
let manager_guard = SYSTEMTRAY_MANAGER.lock().unwrap();
let manager = manager_guard.as_ref().unwrap();

if manager.exit_in_tray {
event.window().hide().unwrap();
api.prevent_close();
}
else {
std::process::exit(1);
}
}
_ => {}
});

app.run(tauri::generate_context!())
.expect("An error occurred while running the application");
app
.run(tauri::generate_context!())
.expect("An error occurred while running the application");
}

fn on_cron_minute_start(_: &str) {

let window_guard = TAURI_WINDOW.lock().unwrap();
let window = window_guard.as_ref().unwrap();
let _ = window.emit_all("CRON_MINUTE_START", ());
Expand Down
6 changes: 4 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ import { RenderResolutionAutomationService } from './services/render-resolution-
import { SleepingAnimationsTabComponent } from './views/dashboard-view/views/osc-automations-view/tabs/sleeping-animations-tab/sleeping-animations-tab.component';
import { OscGeneralTabComponent } from './views/dashboard-view/views/osc-automations-view/tabs/osc-general-tab/osc-general-tab.component';
import { OscGeneralAutomationsService } from './services/osc-general-automations.service';
import { SystemTrayService } from './services/system-tray.service';

[localeEN, localeFR, localeCN_TW, localeNL, localeKO, localeJP].forEach((locale) =>
registerLocaleData(locale)
Expand Down Expand Up @@ -251,6 +252,7 @@ export class AppModule {
private brightnessControlService: BrightnessControlService,
private brightnessControlAutomationService: BrightnessControlAutomationService,
private renderResolutionAutomationService: RenderResolutionAutomationService,
private systemTrayService: SystemTrayService,
private eventLog: EventLogService
) {
this.init();
Expand All @@ -261,8 +263,8 @@ export class AppModule {
await CachedValue.cleanCache();
// Preload assets
await this.preloadAssets();
// Initialize app settings and event log
await Promise.all([this.appSettingsService.init(), this.eventLog.init()]);
// Initialize app settings, event log and system tray settings.
await Promise.all([this.appSettingsService.init(), this.eventLog.init(), this.systemTrayService.init() ]);
// Initialize telemetry and updates
await Promise.all([this.updateService.init(), this.telemetryService.init()]);
// Initialize general utility services
Expand Down
4 changes: 4 additions & 0 deletions src/app/models/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export interface AppSettings {
oscReceivingPort: number;
enableDesktopNotifications: boolean;
enableXSOverlayNotifications: boolean;
exitInSystemTray: boolean;
Copy link
Owner

@Raphiiko Raphiiko May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can you refactor this to closeToSystemTray?

startInSystemTray: boolean;
}
Comment on lines 9 to 14
Copy link
Owner

@Raphiiko Raphiiko May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So these interfaces have a version property that gets bumped whenever they are modified. This is so that people's existing configurations can be migrated once they update.

In this case, two new fields got added, which means the version property should be bumped from 4 to 5, and a migration should be written in src/app/migrations/app-settings.migrations.ts that bumps this version and adds the missing fields. If you take a look at the previous migrations in there, you'll see it's quite simple!


export const APP_SETTINGS_DEFAULT: AppSettings = {
Expand All @@ -23,6 +25,8 @@ export const APP_SETTINGS_DEFAULT: AppSettings = {
oscReceivingPort: 9001,
enableXSOverlayNotifications: false,
enableDesktopNotifications: false,
exitInSystemTray: false,
startInSystemTray: false,
};

export type ExecutableReferenceStatus =
Expand Down
48 changes: 48 additions & 0 deletions src/app/services/system-tray.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Injectable } from '@angular/core';
import { AppSettingsService } from './app-settings.service';
import { debounceTime, filter, first, last, map, pairwise, take } from 'rxjs';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: there's still a few unused imports here :)

import { invoke } from '@tauri-apps/api';

const SYSTEM_TRAY_EXIT_COMMAND = 'set_exit_in_system_tray';
const START_WITH_SYSTEM_TRAY_COMMAND = 'set_start_in_system_tray';

@Injectable({
providedIn: 'root',
})
export class SystemTrayService {
constructor(private readonly _appSettingsService: AppSettingsService) {
}

async init() {
// Update exit in system tray behaviour following the setting.
this._appSettingsService.settings
.pipe(
map(settings => settings.exitInSystemTray),
pairwise(),
filter(([oldVal, newVal]) => oldVal !== newVal),
map(([_, newVal]) => newVal),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
map(([_, newVal]) => newVal),
map(([, newVal]) => newVal),

Nit: in the case of unused array parameters, they can be left empty!

debounceTime(100)
)
.subscribe(exitInSystemTray => this.updateSystemTrayExit(exitInSystemTray));

// Update start in system tray behaviour following the settings.
// Send command only upon loading setings, in order to hide or show the window upon startup.
this._appSettingsService.settings
.pipe(
map(settings => settings.startInSystemTray),
pairwise(),
filter(([oldVal, newVal]) => oldVal !== newVal),
map(([_, newVal]) => newVal),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
map(([_, newVal]) => newVal),
map(([, newVal]) => newVal),

debounceTime(100)
)
.subscribe(startInSystemTray => this.updateSystemTrayStart(startInSystemTray));
}

private async updateSystemTrayExit(exitInSystemTray: boolean) {
await invoke(SYSTEM_TRAY_EXIT_COMMAND, { status: exitInSystemTray });
}

private async updateSystemTrayStart(startInSystemTray: boolean) {
await invoke(START_WITH_SYSTEM_TRAY_COMMAND, { status: startInSystemTray });
}
}
Loading