refactor(windows): handle tray menu events in the main loop (#3446)

Closes #2983
This commit is contained in:
Reactor Scram
2024-01-30 14:55:56 -06:00
committed by GitHub
parent b2b03744b0
commit aa25a46b72
2 changed files with 49 additions and 58 deletions

View File

@@ -222,58 +222,20 @@ async fn accept_deep_links(mut server: deep_link::Server, ctlr_tx: CtlrTx) -> Re
}
fn handle_system_tray_event(app: &tauri::AppHandle, event: TrayMenuEvent) -> Result<()> {
let ctlr_tx = &app
.try_state::<Managed>()
.ok_or_else(|| anyhow!("can't get Managed struct from Tauri"))?
.ctlr_tx;
// TODO: Just handle these in Controller directly: <https://github.com/firezone/firezone/issues/2983>
match event {
TrayMenuEvent::About => {
let win = app
.get_window("about")
.ok_or_else(|| anyhow!("getting handle to About window"))?;
if win.is_visible()? {
win.hide()?;
} else {
win.show()?;
}
}
TrayMenuEvent::CancelSignIn => ctlr_tx.blocking_send(ControllerRequest::CancelSignIn)?,
TrayMenuEvent::Resource { id } => {
ctlr_tx.blocking_send(ControllerRequest::CopyResource(id))?
}
TrayMenuEvent::Settings => {
let win = app
.get_window("settings")
.ok_or_else(|| anyhow!("getting handle to Settings window"))?;
if win.is_visible()? {
// If we close the window here, we can't re-open it, we'd have to fully re-create it. Not needed for MVP - We agreed 100 MB is fine for the GUI client.
win.hide()?;
} else {
win.show()?;
}
}
TrayMenuEvent::SignIn => ctlr_tx.blocking_send(ControllerRequest::SignIn)?,
TrayMenuEvent::SignOut => ctlr_tx.blocking_send(ControllerRequest::SignOut)?,
TrayMenuEvent::Quit => ctlr_tx.blocking_send(ControllerRequest::Quit)?,
}
app.try_state::<Managed>()
.context("can't get Managed struct from Tauri")?
.ctlr_tx
.blocking_send(ControllerRequest::SystemTrayMenu(event))?;
Ok(())
}
pub(crate) enum ControllerRequest {
CancelSignIn,
CopyResource(String),
Disconnected,
DisconnectedTokenExpired,
ExportLogs { path: PathBuf, stem: PathBuf },
GetAdvancedSettings(oneshot::Sender<AdvancedSettings>),
Quit,
SchemeRequest(url::Url),
SignIn,
SignOut,
SystemTrayMenu(TrayMenuEvent),
TunnelReady,
}
@@ -509,6 +471,26 @@ impl Controller {
self.refresh_system_tray_menu()?;
Ok(())
}
fn toggle_window(&self, window: system_tray_menu::Window) -> Result<()> {
let id = match window {
system_tray_menu::Window::About => "about",
system_tray_menu::Window::Settings => "settings",
};
let win = self
.app
.get_window(id)
.ok_or_else(|| anyhow!("getting handle to `{id}` window"))?;
if win.is_visible()? {
// If we close the window here, we can't re-open it, we'd have to fully re-create it. Not needed for MVP - We agreed 100 MB is fine for the GUI client.
win.hide()?;
} else {
win.show()?;
}
Ok(())
}
}
// TODO: After PR #2960 lands, move some of this into `impl Controller`
@@ -553,9 +535,6 @@ async fn run_controller(
break;
};
match req {
Req::CopyResource(id) => if let Err(e) = controller.copy_resource(&id) {
tracing::error!("couldn't copy resource to clipboard: {e:#?}");
}
Req::Disconnected => {
tracing::debug!("connlib disconnected, tearing down Session");
controller.tunnel_ready = false;
@@ -566,10 +545,6 @@ async fn run_controller(
}
controller.refresh_system_tray_menu()?;
}
Req::CancelSignIn | Req::SignOut => {
tracing::info!("User signed out or canceled sign-in");
controller.sign_out()?;
}
Req::DisconnectedTokenExpired => {
tracing::info!("Token expired");
controller.sign_out()?;
@@ -579,11 +554,18 @@ async fn run_controller(
Req::GetAdvancedSettings(tx) => {
tx.send(controller.advanced_settings.clone()).ok();
}
Req::Quit => break,
Req::SchemeRequest(url) => if let Err(e) = controller.handle_deep_link(&url).await {
tracing::error!("couldn't handle deep link: {e:#?}");
}
Req::SignIn => {
Req::SystemTrayMenu(TrayMenuEvent::ToggleWindow(window)) => controller.toggle_window(window)?,
Req::SystemTrayMenu(TrayMenuEvent::CancelSignIn | TrayMenuEvent::SignOut) => {
tracing::info!("User signed out or canceled sign-in");
controller.sign_out()?;
}
Req::SystemTrayMenu(TrayMenuEvent::Resource { id }) => if let Err(e) = controller.copy_resource(&id) {
tracing::error!("couldn't copy resource to clipboard: {e:#?}");
}
Req::SystemTrayMenu(TrayMenuEvent::SignIn) => {
if let Some(req) = controller.auth.start_sign_in()? {
let url = req.to_url(&controller.advanced_settings.auth_base_url);
controller.refresh_system_tray_menu()?;
@@ -594,6 +576,7 @@ async fn run_controller(
)?;
}
}
Req::SystemTrayMenu(TrayMenuEvent::Quit) => break,
Req::TunnelReady => {
controller.tunnel_ready = true;
controller.refresh_system_tray_menu()?;

View File

@@ -4,15 +4,20 @@ use tauri::{CustomMenuItem, SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmen
#[derive(Debug, PartialEq)]
pub(crate) enum Event {
About,
CancelSignIn,
Resource { id: String },
Settings,
SignIn,
SignOut,
ToggleWindow(Window),
Quit,
}
#[derive(Debug, PartialEq)]
pub(crate) enum Window {
About,
Settings,
}
#[derive(thiserror::Error, Debug)]
pub(crate) enum Error {
#[error("the system tray menu item ID is not valid")]
@@ -24,9 +29,9 @@ impl FromStr for Event {
fn from_str(s: &str) -> Result<Self, Error> {
Ok(match s {
"/about" => Self::About,
"/about" => Self::ToggleWindow(Window::About),
"/cancel_sign_in" => Self::CancelSignIn,
"/settings" => Self::Settings,
"/settings" => Self::ToggleWindow(Window::Settings),
"/sign_in" => Self::SignIn,
"/sign_out" => Self::SignOut,
"/quit" => Self::Quit,
@@ -93,12 +98,15 @@ pub(crate) fn signed_out() -> SystemTrayMenu {
#[cfg(test)]
mod tests {
use super::Event;
use super::{Event, Window};
use std::str::FromStr;
#[test]
fn systray_parse() {
assert_eq!(Event::from_str("/about").unwrap(), Event::About);
assert_eq!(
Event::from_str("/about").unwrap(),
Event::ToggleWindow(Window::About)
);
assert_eq!(
Event::from_str("/resource/1234").unwrap(),
Event::Resource {