mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Support enabling multiple notification sinks (#344)
This commit is contained in:
parent
e40a8a8d2e
commit
9a9bdb4862
4 changed files with 106 additions and 18 deletions
|
@ -269,6 +269,8 @@ to use the desktop mechanism (default).
|
||||||
Setting this field to
|
Setting this field to
|
||||||
.Dq Sy bell
|
.Dq Sy bell
|
||||||
will use the terminal bell instead.
|
will use the terminal bell instead.
|
||||||
|
Both can be used via
|
||||||
|
.Dq Sy desktop|bell .
|
||||||
|
|
||||||
.It Sy show_message
|
.It Sy show_message
|
||||||
controls whether to show the message in the desktop notification, and defaults to
|
controls whether to show the message in the desktop notification, and defaults to
|
||||||
|
|
|
@ -398,23 +398,70 @@ pub enum UserDisplayStyle {
|
||||||
DisplayName,
|
DisplayName,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "lowercase")]
|
pub struct NotifyVia {
|
||||||
pub enum NotifyVia {
|
|
||||||
/// Deliver notifications via terminal bell.
|
/// Deliver notifications via terminal bell.
|
||||||
Bell,
|
pub bell: bool,
|
||||||
/// Deliver notifications via desktop mechanism.
|
/// Deliver notifications via desktop mechanism.
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
Desktop,
|
pub desktop: bool,
|
||||||
}
|
}
|
||||||
|
pub struct NotifyViaVisitor;
|
||||||
|
|
||||||
impl Default for NotifyVia {
|
impl Default for NotifyVia {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
#[cfg(not(feature = "desktop"))]
|
Self {
|
||||||
return NotifyVia::Bell;
|
bell: cfg!(not(feature = "desktop")),
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
desktop: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
impl<'de> Visitor<'de> for NotifyViaVisitor {
|
||||||
return NotifyVia::Desktop;
|
type Value = NotifyVia;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a valid notify destination (e.g. \"bell\" or \"desktop\")")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: SerdeError,
|
||||||
|
{
|
||||||
|
let mut via = NotifyVia {
|
||||||
|
bell: false,
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
desktop: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
for value in value.split('|') {
|
||||||
|
match value.to_ascii_lowercase().as_str() {
|
||||||
|
"bell" => {
|
||||||
|
via.bell = true;
|
||||||
|
},
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
"desktop" => {
|
||||||
|
via.desktop = true;
|
||||||
|
},
|
||||||
|
#[cfg(not(feature = "desktop"))]
|
||||||
|
"desktop" => {
|
||||||
|
return Err(E::custom("desktop notification support was compiled out"))
|
||||||
|
},
|
||||||
|
_ => return Err(E::custom("could not parse into a notify destination")),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(via)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for NotifyVia {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_str(NotifyViaVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,6 +1236,29 @@ mod tests {
|
||||||
assert_eq!(run, &exp);
|
assert_eq!(run, &exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_notify_via() {
|
||||||
|
assert_eq!(NotifyVia { bell: false, desktop: true }, NotifyVia::default());
|
||||||
|
assert_eq!(
|
||||||
|
NotifyVia { bell: false, desktop: true },
|
||||||
|
serde_json::from_str(r#""desktop""#).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NotifyVia { bell: true, desktop: false },
|
||||||
|
serde_json::from_str(r#""bell""#).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NotifyVia { bell: true, desktop: true },
|
||||||
|
serde_json::from_str(r#""bell|desktop""#).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NotifyVia { bell: true, desktop: true },
|
||||||
|
serde_json::from_str(r#""desktop|bell""#).unwrap()
|
||||||
|
);
|
||||||
|
assert!(serde_json::from_str::<NotifyVia>(r#""other""#).is_err());
|
||||||
|
assert!(serde_json::from_str::<NotifyVia>(r#""""#).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load_example_config_toml() {
|
fn test_load_example_config_toml() {
|
||||||
let path = PathBuf::from("config.example.toml");
|
let path = PathBuf::from("config.example.toml");
|
||||||
|
|
|
@ -63,11 +63,7 @@ pub async fn register_notifications(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match notify_via {
|
send_notification(¬ify_via, &store, &summary, body.as_deref()).await;
|
||||||
#[cfg(feature = "desktop")]
|
|
||||||
NotifyVia::Desktop => send_notification_desktop(summary, body),
|
|
||||||
NotifyVia::Bell => send_notification_bell(&store).await,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tracing::error!("Failed to extract notification data: {err}")
|
tracing::error!("Failed to extract notification data: {err}")
|
||||||
|
@ -78,22 +74,42 @@ pub async fn register_notifications(
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn send_notification(
|
||||||
|
via: &NotifyVia,
|
||||||
|
store: &AsyncProgramStore,
|
||||||
|
summary: &str,
|
||||||
|
body: Option<&str>,
|
||||||
|
) {
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
if via.desktop {
|
||||||
|
send_notification_desktop(summary, body);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "desktop"))]
|
||||||
|
{
|
||||||
|
let _ = (summary, body, IAMB_XDG_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if via.bell {
|
||||||
|
send_notification_bell(store).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn send_notification_bell(store: &AsyncProgramStore) {
|
async fn send_notification_bell(store: &AsyncProgramStore) {
|
||||||
let mut locked = store.lock().await;
|
let mut locked = store.lock().await;
|
||||||
locked.application.ring_bell = true;
|
locked.application.ring_bell = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
fn send_notification_desktop(summary: String, body: Option<String>) {
|
fn send_notification_desktop(summary: &str, body: Option<&str>) {
|
||||||
let mut desktop_notification = notify_rust::Notification::new();
|
let mut desktop_notification = notify_rust::Notification::new();
|
||||||
desktop_notification
|
desktop_notification
|
||||||
.summary(&summary)
|
.summary(summary)
|
||||||
.appname(IAMB_XDG_NAME)
|
.appname(IAMB_XDG_NAME)
|
||||||
.icon(IAMB_XDG_NAME)
|
.icon(IAMB_XDG_NAME)
|
||||||
.action("default", "default");
|
.action("default", "default");
|
||||||
|
|
||||||
if let Some(body) = body {
|
if let Some(body) = body {
|
||||||
desktop_notification.body(&body);
|
desktop_notification.body(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = desktop_notification.show() {
|
if let Err(err) = desktop_notification.show() {
|
||||||
|
|
|
@ -191,7 +191,7 @@ pub fn mock_tunables() -> TunableValues {
|
||||||
message_user_color: false,
|
message_user_color: false,
|
||||||
notifications: Notifications {
|
notifications: Notifications {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
via: NotifyVia::Desktop,
|
via: NotifyVia::default(),
|
||||||
show_message: true,
|
show_message: true,
|
||||||
},
|
},
|
||||||
image_preview: None,
|
image_preview: None,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue