refactor: improve tray icon/menu implementation.

This commit is contained in:
Timofey Gelazoniya 2024-09-06 02:06:53 +03:00
parent 559b0e843c
commit 0a4c10de34
Signed by: zeldon
GPG Key ID: 047886915281DD2A
2 changed files with 65 additions and 47 deletions

View File

@ -27,7 +27,6 @@ fn main() {
// Hide the console window
winuser::ShowWindow(wincon::GetConsoleWindow(), winuser::SW_HIDE);
}
std::env::set_var("RUST_LOG", "trace");
pretty_env_logger::init();

View File

@ -12,7 +12,10 @@ use tray_icon::{
menu::{Menu, MenuEvent, MenuItem},
TrayIcon, TrayIconBuilder,
};
use winapi::um::{wincon::GetConsoleWindow, winuser::{self, ShowWindow, SW_SHOW}};
use winapi::um::{
wincon::GetConsoleWindow,
winuser::{self, ShowWindow, SW_SHOW},
};
const BATTERY_UPDATE_INTERVAL: std::time::Duration = std::time::Duration::from_secs(60);
const DEVICE_FETCH_INTERVAL: std::time::Duration = std::time::Duration::from_secs(5);
@ -39,12 +42,59 @@ impl MemoryDevice {
}
}
pub struct TrayInner {
tray_icon: Rc<Mutex<Option<TrayIcon>>>,
console_state: Arc<Mutex<bool>>,
menu_items: Arc<Mutex<Vec<MenuItem>>>,
}
impl TrayInner {
fn new() -> Self {
Self {
tray_icon: Rc::new(Mutex::new(None)),
console_state: Arc::new(Mutex::new(false)),
menu_items: Arc::new(Mutex::new(Vec::new())),
}
}
fn create_menu(&self) -> Menu {
let tray_menu = Menu::new();
let show_console_item = MenuItem::new("Show Log Window", true, None);
let quit_item = MenuItem::new("Exit", true, None);
let mut menu_items = self.menu_items.lock().unwrap();
menu_items.push(show_console_item);
menu_items.push(quit_item);
tray_menu
.append_items(&[&menu_items[0], &menu_items[1]])
.unwrap();
tray_menu
}
fn build_tray(
tray_icon: &Rc<Mutex<Option<TrayIcon>>>,
tray_menu: &Menu,
icon: tray_icon::Icon,
) {
let tray_builder = TrayIconBuilder::new()
.with_menu(Box::new(tray_menu.clone()))
.with_tooltip("Service is running")
.with_icon(icon)
.build();
match tray_builder {
Ok(tray) => *tray_icon.lock().unwrap() = Some(tray),
Err(err) => error!("Failed to create tray icon: {}", err),
}
}
}
pub struct TrayApp {
device_manager: Arc<Mutex<DeviceManager>>,
devices: Arc<Mutex<HashMap<u32, MemoryDevice>>>,
tray_icon: Rc<Mutex<Option<TrayIcon>>>,
console_state: Arc<Mutex<bool>>,
menu_items: Arc<Mutex<Vec<MenuItem>>>
tray_inner: TrayInner,
}
impl TrayApp {
@ -52,16 +102,14 @@ impl TrayApp {
Self {
device_manager: Arc::new(Mutex::new(DeviceManager::new())),
devices: Arc::new(Mutex::new(HashMap::new())),
tray_icon: Rc::new(Mutex::new(None)),
console_state: Arc::new(Mutex::new(false)),
menu_items: Arc::new(Mutex::new(Vec::new()))
tray_inner: TrayInner::new(),
}
}
pub fn run(&self) {
let icon = Self::create_icon();
let event_loop = EventLoopBuilder::new().build();
let tray_menu = self.create_menu();
let tray_menu = self.tray_inner.create_menu();
let (sender, receiver) = mpsc::channel();
@ -82,20 +130,6 @@ impl TrayApp {
tray_icon::Icon::from_rgba(rgba, width, height).expect("Failed to create icon")
}
fn create_menu(&self) -> Menu {
let tray_menu = Menu::new();
let show_console_item = MenuItem::new("Show Log Window", true, None);
let quit_item = MenuItem::new("Exit", true, None);
let mut menu_items = self.menu_items.lock().unwrap();
menu_items.push(show_console_item);
menu_items.push(quit_item);
tray_menu.append_items(&[&menu_items[0], &menu_items[1]]).unwrap();
tray_menu
}
fn spawn_device_fetch_thread(&self, tx: mpsc::Sender<Vec<u32>>) {
let devices = Arc::clone(&self.devices);
let device_manager = Arc::clone(&self.device_manager);
@ -125,7 +159,7 @@ impl TrayApp {
}
}
}
if !connected_devices.is_empty() {
tx.send(connected_devices).unwrap();
}
@ -151,11 +185,11 @@ impl TrayApp {
tray_menu: Menu,
rx: mpsc::Receiver<Vec<u32>>,
) {
let tray_icon = Rc::clone(&self.tray_icon);
let devices = Arc::clone(&self.devices);
let device_manager = Arc::clone(&self.device_manager);
let console_state = Arc::clone(&self.console_state);
let menu_items = Arc::clone(&self.menu_items);
let tray_icon = Rc::clone(&self.tray_inner.tray_icon);
let console_state = Arc::clone(&self.tray_inner.console_state);
let menu_items = Arc::clone(&self.tray_inner.menu_items);
let menu_channel = MenuEvent::receiver();
@ -169,7 +203,9 @@ impl TrayApp {
}
if let tao::event::Event::NewEvents(tao::event::StartCause::Init) = event {
Self::build_tray(&tray_icon, &tray_menu, icon.clone());
// We create the icon once the event loop is actually running
// to prevent issues like https://github.com/tauri-apps/tray-icon/issues/90
TrayInner::build_tray(&tray_icon, &tray_menu, icon.clone());
}
if let Ok(event) = menu_channel.try_recv() {
@ -182,12 +218,12 @@ impl TrayApp {
let mut visible = console_state.lock().unwrap();
if *visible {
unsafe {ShowWindow(GetConsoleWindow(), winuser::SW_HIDE)};
unsafe { ShowWindow(GetConsoleWindow(), winuser::SW_HIDE) };
show_console_item.set_text("Show Log Window");
trace!("hiding log window");
*visible = false;
} else {
unsafe {ShowWindow(GetConsoleWindow(), SW_SHOW)};
unsafe { ShowWindow(GetConsoleWindow(), SW_SHOW) };
show_console_item.set_text("Hide Log Window");
trace!("showing log window");
*visible = true
@ -201,23 +237,6 @@ impl TrayApp {
});
}
fn build_tray(
tray_icon: &Rc<Mutex<Option<TrayIcon>>>,
tray_menu: &Menu,
icon: tray_icon::Icon,
) {
let tray_builder = TrayIconBuilder::new()
.with_menu(Box::new(tray_menu.clone()))
.with_tooltip("Service is running")
.with_icon(icon)
.build();
match tray_builder {
Ok(tray) => *tray_icon.lock().unwrap() = Some(tray),
Err(err) => error!("Failed to create tray icon: {}", err),
}
}
fn update(
devices: &Arc<Mutex<HashMap<u32, MemoryDevice>>>,
manager: &Arc<Mutex<DeviceManager>>,