Skip to content

Commit

Permalink
feat: allow playing default notification sound
Browse files Browse the repository at this point in the history
  • Loading branch information
amrbashir authored and hoodie committed Jul 23, 2023
1 parent 577fbdd commit ee19343
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 33 deletions.
9 changes: 9 additions & 0 deletions examples/sound.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
use mac_notification_sys::*;

fn main() {

Notification::default()
.title("🔔")
.message("Ping")
.sound("Ping")
.send()
.unwrap();

Notification::default()
.title("🐟")
.message("Submarine")
.sound("Submarine")
.send()
.unwrap();

Notification::default()
.title("🥱")
.message("Default")
.sound(Sound::Default)
.send()
.unwrap();
}
11 changes: 9 additions & 2 deletions objc/notify.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,16 @@ BOOL setApplication(NSString* newbundleIdentifier)
userNotification.informativeText = message;

// Notification sound
if (options[@"sound"] && ![options[@"sound"] isEqualToString:@""] && ![options[@"sound"] isEqualToString:@"_mute"])
if (options[@"sound"] && ![options[@"sound"] isEqualToString:@""])
{
userNotification.soundName = options[@"sound"];
if ([options[@"sound"] isEqualToString:@"NSUserNotificationDefaultSoundName"])
{
userNotification.soundName = NSUserNotificationDefaultSoundName;
}
else
{
userNotification.soundName = options[@"sound"];
}
}

// Delivery Date/Schedule
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub mod error;
mod notification;

use error::{ApplicationError, NotificationError, NotificationResult};
pub use notification::{MainButton, Notification, NotificationResponse};
pub use notification::{MainButton, Notification, NotificationResponse, Sound};
use objc_foundation::{INSDictionary, INSString, NSString};
use std::ops::Deref;
use std::sync::Once;
Expand Down
66 changes: 36 additions & 30 deletions src/notification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use objc_foundation::{INSDictionary, INSString, NSDictionary, NSString};
use objc_id::Id;
use std::default::Default;
use std::ops::Deref;
use std::path::PathBuf;

use crate::error::{NotificationError, NotificationResult};
use crate::{ensure, ensure_application_set, sys};
Expand Down Expand Up @@ -43,6 +42,21 @@ pub enum MainButton<'a> {
Response(&'a str),
}

#[derive(Clone)]
pub enum Sound {
Default,
Custom(String),
}

impl<I> From<I> for Sound
where
I: ToString,
{
fn from(value: I) -> Self {
Sound::Custom(value.to_string())
}
}

/// Options to further customize the notification
#[derive(Clone, Default)]
pub struct Notification<'a> {
Expand All @@ -54,7 +68,7 @@ pub struct Notification<'a> {
pub(crate) app_icon: Option<&'a str>,
pub(crate) content_image: Option<&'a str>,
pub(crate) delivery_date: Option<f64>,
pub(crate) sound: Option<&'a str>,
pub(crate) sound: Option<Sound>,
pub(crate) asynchronous: Option<bool>,
}

Expand Down Expand Up @@ -156,29 +170,34 @@ impl<'a> Notification<'a> {
self
}

/// Play a system sound when the notification is delivered
///
/// Play a system sound when the notification is delivered. Use `NSUserNotificationDefaultSoundName` to play the default sound.
/// # Example:
///
/// ```no_run
/// # use mac_notification_sys::*;
/// let _ = Notification::new().sound("Blow");
/// ```
pub fn sound(&mut self, sound: &'a str) -> &mut Self {
self.sound = Some(sound);
pub fn sound<S>(&mut self, sound: S) -> &mut Self
where
S: Into<Sound>,
{
self.sound = Some(sound.into());
self
}

/// Play a system sound when the notification is delivered
/// Play a system sound when the notification is delivered. Use `NSUserNotificationDefaultSoundName` to play the default sound.
///
/// # Example:
///
/// ```no_run
/// # use mac_notification_sys::*;
/// let _ = Notification::new().sound("Blow");
/// ```
pub fn maybe_sound(&mut self, sound: Option<&'a str>) -> &mut Self {
self.sound = sound;
pub fn maybe_sound<S>(&mut self, sound: Option<S>) -> &mut Self
where
S: Into<Sound>,
{
self.sound = sound.map(Into::into);
self
}

Expand Down Expand Up @@ -210,6 +229,7 @@ impl<'a> Notification<'a> {
&*NSString::from_str("deliveryDate"),
&*NSString::from_str("asynchronous"),
&*NSString::from_str("sound"),
&*NSString::from_str("soundIsCustom"),
];
let (main_button_label, actions, is_response): (&str, &[&str], bool) =
match &self.main_button {
Expand All @@ -223,6 +243,12 @@ impl<'a> Notification<'a> {
None => ("", &[], false),
};

let sound = match self.sound {
Some(Sound::Custom(ref name)) => name.as_str(),
Some(Sound::Default) => "NSUserNotificationDefaultSoundName",
None => "",
};

let vals = vec![
NSString::from_str(main_button_label),
// TODO: Find a way to support NSArray as a NSDictionary Value rather than JUST NSString so I don't have to convert array to string and back
Expand All @@ -241,10 +267,7 @@ impl<'a> Notification<'a> {
Some(true) => "yes",
_ => "no",
}),
NSString::from_str(match self.sound {
Some(sound) if check_sound(sound) => sound,
_ => "_mute",
}),
NSString::from_str(sound),
];
NSDictionary::from_keys_and_objects(keys, vals)
}
Expand Down Expand Up @@ -335,20 +358,3 @@ impl NotificationResponse {
}
}
}

pub(crate) fn check_sound(sound_name: &str) -> bool {
dirs_next::home_dir()
.map(|path| path.join("/Library/Sounds/"))
.into_iter()
.chain(
[
"/Library/Sounds/",
"/Network/Library/Sounds/",
"/System/Library/Sounds/",
]
.iter()
.map(PathBuf::from),
)
.map(|sound_path| sound_path.join(format!("{}.aiff", sound_name)))
.any(|some_path| some_path.exists())
}

0 comments on commit ee19343

Please sign in to comment.