Support enabling multiple notification sinks (#344)

This commit is contained in:
Nemo157 2024-09-17 07:15:36 +02:00 committed by GitHub
parent e40a8a8d2e
commit 9a9bdb4862
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 106 additions and 18 deletions

View file

@ -398,23 +398,70 @@ pub enum UserDisplayStyle {
DisplayName,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum NotifyVia {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct NotifyVia {
/// Deliver notifications via terminal bell.
Bell,
pub bell: bool,
/// Deliver notifications via desktop mechanism.
#[cfg(feature = "desktop")]
Desktop,
pub desktop: bool,
}
pub struct NotifyViaVisitor;
impl Default for NotifyVia {
fn default() -> Self {
#[cfg(not(feature = "desktop"))]
return NotifyVia::Bell;
Self {
bell: cfg!(not(feature = "desktop")),
#[cfg(feature = "desktop")]
desktop: true,
}
}
}
#[cfg(feature = "desktop")]
return NotifyVia::Desktop;
impl<'de> Visitor<'de> for NotifyViaVisitor {
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);
}
#[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]
fn test_load_example_config_toml() {
let path = PathBuf::from("config.example.toml");

View file

@ -63,11 +63,7 @@ pub async fn register_notifications(
return;
}
match notify_via {
#[cfg(feature = "desktop")]
NotifyVia::Desktop => send_notification_desktop(summary, body),
NotifyVia::Bell => send_notification_bell(&store).await,
}
send_notification(&notify_via, &store, &summary, body.as_deref()).await;
},
Err(err) => {
tracing::error!("Failed to extract notification data: {err}")
@ -78,22 +74,42 @@ pub async fn register_notifications(
.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) {
let mut locked = store.lock().await;
locked.application.ring_bell = true;
}
#[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();
desktop_notification
.summary(&summary)
.summary(summary)
.appname(IAMB_XDG_NAME)
.icon(IAMB_XDG_NAME)
.action("default", "default");
if let Some(body) = body {
desktop_notification.body(&body);
desktop_notification.body(body);
}
if let Err(err) = desktop_notification.show() {

View file

@ -191,7 +191,7 @@ pub fn mock_tunables() -> TunableValues {
message_user_color: false,
notifications: Notifications {
enabled: false,
via: NotifyVia::Desktop,
via: NotifyVia::default(),
show_message: true,
},
image_preview: None,