use std::sync::OnceLock;
use objc2_user_notifications::{
UNNotificationDefaultActionIdentifier, UNNotificationDismissActionIdentifier,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CloseReason {
Expired,
Dismissed,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NotificationResponse {
pub notification_id: String,
pub action_identifier: String,
pub reply_text: Option<String>,
pub close_reason: Option<CloseReason>,
}
fn dismiss_action_id() -> &'static str {
static CACHED: OnceLock<String> = OnceLock::new();
CACHED.get_or_init(|| {
unsafe { UNNotificationDismissActionIdentifier.to_string() }
})
}
fn default_action_id() -> &'static str {
static CACHED: OnceLock<String> = OnceLock::new();
CACHED.get_or_init(|| {
unsafe { UNNotificationDefaultActionIdentifier.to_string() }
})
}
impl NotificationResponse {
pub(crate) fn from_objc(
notification_id: String,
action_id: String,
reply_text: Option<String>,
) -> Self {
let close_reason = if action_id == dismiss_action_id() {
Some(CloseReason::Dismissed)
} else {
None
};
Self {
notification_id,
action_identifier: action_id,
reply_text,
close_reason,
}
}
pub(crate) fn timed_out(notification_id: String) -> Self {
Self {
notification_id,
action_identifier: String::new(),
reply_text: None,
close_reason: Some(CloseReason::Expired),
}
}
pub(crate) fn dismissed(notification_id: String) -> Self {
Self {
notification_id,
action_identifier: String::new(),
reply_text: None,
close_reason: Some(CloseReason::Dismissed),
}
}
pub fn is_timed_out(&self) -> bool {
self.close_reason == Some(CloseReason::Expired)
}
pub fn is_default_action(&self) -> bool {
self.action_identifier == default_action_id()
}
pub fn is_dismiss_action(&self) -> bool {
self.close_reason == Some(CloseReason::Dismissed)
}
pub fn is_reply(&self) -> bool {
self.reply_text.is_some()
}
}