use async_trait::async_trait;
use origin_domain::Result;
use std::fmt::Debug;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TrayMenuItem {
pub id: String,
pub label: String,
pub enabled: bool,
}
impl TrayMenuItem {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self {
id: id.into(),
label: label.into(),
enabled: true,
}
}
pub fn disabled(mut self) -> Self {
self.enabled = false;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TrayBadge {
None,
Attention,
Count(u32),
}
#[async_trait]
pub trait TrayService: Debug + Send + Sync + 'static {
async fn set_title(&self, title: &str) -> Result<()>;
async fn set_badge(&self, badge: TrayBadge) -> Result<()>;
async fn set_menu(&self, items: Vec<TrayMenuItem>) -> Result<()>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NoopTrayService;
#[async_trait]
impl TrayService for NoopTrayService {
async fn set_title(&self, title: &str) -> Result<()> {
tracing::debug!(title, "tray title — dropped (noop service)");
Ok(())
}
async fn set_badge(&self, badge: TrayBadge) -> Result<()> {
tracing::debug!(?badge, "tray badge — dropped (noop service)");
Ok(())
}
async fn set_menu(&self, items: Vec<TrayMenuItem>) -> Result<()> {
tracing::debug!(count = items.len(), "tray menu — dropped (noop service)");
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn the_noop_service_accepts_everything_without_error() {
let tray: &dyn TrayService = &NoopTrayService;
tray.set_title("demo").await.unwrap();
tray.set_badge(TrayBadge::Count(3)).await.unwrap();
tray.set_menu(vec![
TrayMenuItem::new("show", "Show window"),
TrayMenuItem::new("quit", "Quit"),
])
.await
.unwrap();
}
}