feat: implement desktop notifications with comprehensive filtering
Implemented Phase 10 (Desktop Notifications) with three stages: notify-rust integration, smart filtering, and production polish. Stage 1 - Base Implementation: - Add NotificationManager module (src/notifications.rs, 350+ lines) - Integrate notify-rust 4.11 with feature flag "notifications" - Implement NotificationsConfig in config.toml (enabled, only_mentions, show_preview) - Add notification_manager field to TdClient - Create configure_notifications() method for config integration - Hook into handle_new_message_update() to send notifications - Send notifications for messages outside current chat - Format notification body with sender name and message preview Stage 2 - Smart Filtering: - Sync muted chats from Telegram (sync_muted_chats method) - Filter muted chats from notifications automatically - Add MessageInfo::has_mention() to detect @username mentions - Implement only_mentions filter (notify only when mentioned) - Beautify media labels with emojis (📷 📹 🎤 🎨 📎 etc.) - Support 10+ media types in notification preview Stage 3 - Production Polish: - Add graceful error handling (no panics on notification failure) - Implement comprehensive logging (tracing::debug!/warn!) - Add timeout_ms configuration (0 = system default) - Add urgency configuration (low/normal/critical, Linux only) - Platform-specific #[cfg] for urgency support - Log all notification skip reasons at debug level Hotkey Change: - Move profile view from 'i' to Ctrl+i to avoid conflicts Technical Details: - Cross-platform support (macOS, Linux, Windows) - Feature flag for optional notifications support - Graceful fallback when notifications unavailable - LRU-friendly muted chats sync - Test coverage for all core notification logic - All 75 tests passing Files Changed: - NEW: src/notifications.rs - Complete NotificationManager - NEW: config.example.toml - Example configuration with notifications - Modified: Cargo.toml - Add notify-rust 4.11 dependency - Modified: src/config/mod.rs - Add NotificationsConfig struct - Modified: src/tdlib/types.rs - Add has_mention() method - Modified: src/tdlib/client.rs - Add notification integration - Modified: src/tdlib/update_handlers.rs - Hook notifications - Modified: src/config/keybindings.rs - Change profile to Ctrl+i - Modified: tests/* - Add notification config to tests Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -230,8 +230,8 @@ impl Keybindings {
|
||||
|
||||
// Profile
|
||||
bindings.insert(Command::OpenProfile, vec![
|
||||
KeyBinding::new(KeyCode::Char('i')),
|
||||
KeyBinding::new(KeyCode::Char('ш')), // RU
|
||||
KeyBinding::with_ctrl(KeyCode::Char('i')),
|
||||
KeyBinding::with_ctrl(KeyCode::Char('ш')), // RU
|
||||
]);
|
||||
|
||||
Self { bindings }
|
||||
|
||||
@@ -34,6 +34,10 @@ pub struct Config {
|
||||
/// Горячие клавиши.
|
||||
#[serde(default)]
|
||||
pub keybindings: Keybindings,
|
||||
|
||||
/// Настройки desktop notifications.
|
||||
#[serde(default)]
|
||||
pub notifications: NotificationsConfig,
|
||||
}
|
||||
|
||||
/// Общие настройки приложения.
|
||||
@@ -71,6 +75,31 @@ pub struct ColorsConfig {
|
||||
pub reaction_other: String,
|
||||
}
|
||||
|
||||
/// Настройки desktop notifications.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NotificationsConfig {
|
||||
/// Включить/выключить уведомления
|
||||
#[serde(default = "default_notifications_enabled")]
|
||||
pub enabled: bool,
|
||||
|
||||
/// Уведомлять только при @упоминаниях
|
||||
#[serde(default)]
|
||||
pub only_mentions: bool,
|
||||
|
||||
/// Показывать превью текста сообщения
|
||||
#[serde(default = "default_show_preview")]
|
||||
pub show_preview: bool,
|
||||
|
||||
/// Продолжительность показа уведомления (миллисекунды)
|
||||
/// 0 = системное значение по умолчанию
|
||||
#[serde(default = "default_notification_timeout")]
|
||||
pub timeout_ms: i32,
|
||||
|
||||
/// Уровень важности: "low", "normal", "critical"
|
||||
#[serde(default = "default_notification_urgency")]
|
||||
pub urgency: String,
|
||||
}
|
||||
|
||||
// Дефолтные значения
|
||||
fn default_timezone() -> String {
|
||||
"+03:00".to_string()
|
||||
@@ -96,6 +125,22 @@ fn default_reaction_other_color() -> String {
|
||||
"gray".to_string()
|
||||
}
|
||||
|
||||
fn default_notifications_enabled() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_show_preview() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_notification_timeout() -> i32 {
|
||||
5000 // 5 seconds
|
||||
}
|
||||
|
||||
fn default_notification_urgency() -> String {
|
||||
"normal".to_string()
|
||||
}
|
||||
|
||||
impl Default for GeneralConfig {
|
||||
fn default() -> Self {
|
||||
Self { timezone: default_timezone() }
|
||||
@@ -114,6 +159,17 @@ impl Default for ColorsConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NotificationsConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: default_notifications_enabled(),
|
||||
only_mentions: false,
|
||||
show_preview: default_show_preview(),
|
||||
timeout_ms: default_notification_timeout(),
|
||||
urgency: default_notification_urgency(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
@@ -121,6 +177,7 @@ impl Default for Config {
|
||||
general: GeneralConfig::default(),
|
||||
colors: ColorsConfig::default(),
|
||||
keybindings: Keybindings::default(),
|
||||
notifications: NotificationsConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user