Skip to main content

aster/notifications/
manager.rs

1//! 通知管理器
2//!
3//! 管理通知的发送、存储和状态
4
5use super::desktop::{play_sound, send_desktop_notification};
6use super::types::*;
7use std::sync::{Arc, RwLock};
8use std::time::{SystemTime, UNIX_EPOCH};
9
10/// 通知管理器
11pub struct NotificationManager {
12    /// 配置
13    config: NotificationConfig,
14    /// 通知列表
15    notifications: Arc<RwLock<Vec<Notification>>>,
16    /// 最大通知数
17    max_notifications: usize,
18}
19
20impl NotificationManager {
21    /// 创建新的通知管理器
22    pub fn new(config: NotificationConfig) -> Self {
23        Self {
24            config,
25            notifications: Arc::new(RwLock::new(Vec::new())),
26            max_notifications: 100,
27        }
28    }
29
30    /// 检查是否启用
31    pub fn is_enabled(&self) -> bool {
32        if !self.config.enabled {
33            return false;
34        }
35
36        // 检查静音时段
37        if let (Some(start), Some(end)) =
38            (self.config.quiet_hours_start, self.config.quiet_hours_end)
39        {
40            use chrono::Timelike;
41            let now = chrono::Local::now().hour() as u8;
42            if start <= end {
43                if now >= start && now < end {
44                    return false;
45                }
46            } else {
47                // 跨夜(如 22-06)
48                if now >= start || now < end {
49                    return false;
50                }
51            }
52        }
53
54        true
55    }
56
57    /// 检查优先级
58    fn meets_priority(&self, notification_type: NotificationType) -> bool {
59        let Some(min_priority) = self.config.min_priority else {
60            return true;
61        };
62
63        let priority_order = [
64            NotificationType::Info,
65            NotificationType::Success,
66            NotificationType::Warning,
67            NotificationType::Error,
68        ];
69
70        let type_index = priority_order
71            .iter()
72            .position(|&t| t == notification_type)
73            .unwrap_or(0);
74        let min_index = priority_order
75            .iter()
76            .position(|&t| t == min_priority)
77            .unwrap_or(0);
78
79        type_index >= min_index
80    }
81
82    /// 发送通知
83    pub fn notify(
84        &self,
85        title: &str,
86        message: &str,
87        notification_type: NotificationType,
88        kind: NotificationKind,
89    ) -> Option<Notification> {
90        if !self.is_enabled() || !self.meets_priority(notification_type) {
91            return None;
92        }
93
94        let timestamp = SystemTime::now()
95            .duration_since(UNIX_EPOCH)
96            .map(|d| d.as_millis() as u64)
97            .unwrap_or(0);
98
99        let notification = Notification {
100            id: format!("notif_{}_{}", timestamp, rand::random::<u32>()),
101            notification_type,
102            kind,
103            title: title.to_string(),
104            message: message.to_string(),
105            timestamp,
106            read: false,
107            actions: Vec::new(),
108        };
109
110        // 添加到列表
111        if let Ok(mut notifications) = self.notifications.write() {
112            notifications.insert(0, notification.clone());
113            if notifications.len() > self.max_notifications {
114                notifications.truncate(self.max_notifications);
115            }
116        }
117
118        // 发送桌面通知
119        if self.config.desktop_notifications {
120            let _ = send_desktop_notification(&notification);
121        }
122
123        // 播放声音
124        if self.config.sound_enabled {
125            let _ = play_sound(notification_type);
126        }
127
128        Some(notification)
129    }
130
131    /// 获取所有通知
132    pub fn get_all(&self) -> Vec<Notification> {
133        self.notifications
134            .read()
135            .map(|n| n.clone())
136            .unwrap_or_default()
137    }
138
139    /// 获取未读通知
140    pub fn get_unread(&self) -> Vec<Notification> {
141        self.notifications
142            .read()
143            .map(|n| n.iter().filter(|n| !n.read).cloned().collect())
144            .unwrap_or_default()
145    }
146
147    /// 获取未读数量
148    pub fn get_unread_count(&self) -> usize {
149        self.notifications
150            .read()
151            .map(|n| n.iter().filter(|n| !n.read).count())
152            .unwrap_or(0)
153    }
154
155    /// 标记为已读
156    pub fn mark_as_read(&self, id: &str) -> bool {
157        if let Ok(mut notifications) = self.notifications.write() {
158            if let Some(n) = notifications.iter_mut().find(|n| n.id == id) {
159                n.read = true;
160                return true;
161            }
162        }
163        false
164    }
165
166    /// 标记全部已读
167    pub fn mark_all_as_read(&self) {
168        if let Ok(mut notifications) = self.notifications.write() {
169            for n in notifications.iter_mut() {
170                n.read = true;
171            }
172        }
173    }
174
175    /// 清空所有通知
176    pub fn clear(&self) {
177        if let Ok(mut notifications) = self.notifications.write() {
178            notifications.clear();
179        }
180    }
181
182    /// 便捷方法:发送信息通知
183    pub fn info(&self, title: &str, message: &str) -> Option<Notification> {
184        self.notify(
185            title,
186            message,
187            NotificationType::Info,
188            NotificationKind::Custom,
189        )
190    }
191
192    /// 便捷方法:发送成功通知
193    pub fn success(&self, title: &str, message: &str) -> Option<Notification> {
194        self.notify(
195            title,
196            message,
197            NotificationType::Success,
198            NotificationKind::TaskComplete,
199        )
200    }
201
202    /// 便捷方法:发送警告通知
203    pub fn warn(&self, title: &str, message: &str) -> Option<Notification> {
204        self.notify(
205            title,
206            message,
207            NotificationType::Warning,
208            NotificationKind::Custom,
209        )
210    }
211
212    /// 便捷方法:发送错误通知
213    pub fn error(&self, title: &str, message: &str) -> Option<Notification> {
214        self.notify(
215            title,
216            message,
217            NotificationType::Error,
218            NotificationKind::Error,
219        )
220    }
221}
222
223impl Default for NotificationManager {
224    fn default() -> Self {
225        Self::new(NotificationConfig::default())
226    }
227}