Skip to content

Commit

Permalink
Merge pull request #50 from amrbashir/feat/default-sound
Browse files Browse the repository at this point in the history
feat: allow playing default notification sound
  • Loading branch information
hoodie authored Jul 23, 2023
2 parents 577fbdd + c0ffeec commit b655bf0
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 32 deletions.
8 changes: 8 additions & 0 deletions examples/sound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ fn main() {
.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
78 changes: 49 additions & 29 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,24 @@ pub enum MainButton<'a> {
Response(&'a str),
}

/// Helper to determine whether you want to play the default sound or custom one
#[derive(Clone)]
pub enum Sound {
/// notification plays the sound [`NSUserNotificationDefaultSoundName`](https://developer.apple.com/documentation/foundation/nsusernotification/nsusernotificationdefaultsoundname)
Default,
/// notification plays your custom sound
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 +71,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 +173,46 @@ impl<'a> Notification<'a> {
self
}

/// Play a system sound when the notification is delivered
/// Play the default sound `"NSUserNotificationDefaultSoundName"` system sound when the notification is delivered.
/// # Example:
///
/// ```no_run
/// # use mac_notification_sys::*;
/// let _ = Notification::new().sound("Blow");
/// ```
pub fn default_sound(&mut self) -> &mut Self {
self.sound = Some(Sound::Default);
self
}

/// Play a system sound when the notification is delivered. Use [`Sound::Default`] 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 [`Sound::Default`] 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 @@ -223,6 +257,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 +281,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 +372,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 b655bf0

Please sign in to comment.