//! Notifications toast Windows. //! //! Affiche des notifications natives Windows via l'API WinRT (winrt-notification). //! Equivalent de agent_v1/ui/notifications.py. //! //! Sur Linux/macOS : les notifications sont simplement affichees en console (log). //! Le crate winrt-notification n'est disponible que sur Windows. use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; /// Intervalle minimum entre deux notifications identiques (en secondes). /// Evite le spam de notifications si le meme evenement se repete. const MIN_INTERVAL_SECS: u64 = 5; /// Timestamp de la derniere notification envoyee (rate limiting). static LAST_NOTIFY_TIME: AtomicU64 = AtomicU64::new(0); /// Affiche une notification toast native. /// /// Sur Windows : utilise winrt-notification pour les toasts natifs. /// Sur les autres OS : affiche en console. /// Rate-limited : pas plus d'une notification toutes les 5 secondes. pub fn notify(title: &str, message: &str) { // Rate limiting let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap_or_default() .as_secs(); let last = LAST_NOTIFY_TIME.load(Ordering::Relaxed); if now - last < MIN_INTERVAL_SECS { return; } LAST_NOTIFY_TIME.store(now, Ordering::Relaxed); // Log console dans tous les cas println!("[NOTIFICATION] {} : {}", title, message); // Toast natif Windows #[cfg(windows)] { notify_windows(title, message); } } /// Implementation Windows via winrt-notification. #[cfg(windows)] fn notify_windows(title: &str, message: &str) { use winrt_notification::{Toast, Sound}; let result = Toast::new(Toast::POWERSHELL_APP_ID) .title(title) .text1(message) .sound(Some(Sound::Default)) .show(); if let Err(e) = result { eprintln!("[NOTIFICATION] Erreur toast Windows : {:?}", e); } } // --- Notifications predefinies (equivalent Python) --- /// Notification de bienvenue au demarrage. pub fn greet() { notify( "Lea - Assistant IA", "Bonjour ! Lea est prete. (IA)\nJe peux observer et automatiser vos taches.", ); } /// Notification de debut de session d'enregistrement. pub fn session_started(name: &str) { notify( "Enregistrement demarre", &format!( "C'est parti ! Je regarde et je memorise.\nSession : {}", name ), ); } /// Notification de fin de session d'enregistrement. pub fn session_ended(actions_count: u32) { notify( "Enregistrement termine", &format!( "C'est note ! J'ai compris les {} etapes.", actions_count ), ); } /// Notification de debut de replay. pub fn replay_started(name: &str) { notify( "Replay en cours", &format!( "Le systeme d'IA execute la tache...\nWorkflow : {}", name ), ); } /// Notification de fin de replay. pub fn replay_finished(success: bool) { if success { notify("Replay termine", "C'est fait ! La tache a ete executee avec succes."); } else { notify( "Replay echoue", "Hmm, j'ai eu un souci. Verifiez le resultat.", ); } } /// Notification de changement de connexion. pub fn connection_changed(connected: bool) { if connected { notify("Connexion etablie", "Connectee au serveur RPA Vision."); } else { notify( "Connexion perdue", "Connexion au serveur perdue. Tentative de reconnexion...", ); } } /// Notification d'arret d'urgence. pub fn emergency_stop_activated() { notify( "ARRET D'URGENCE", "Toutes les operations ont ete arretees immediatement.", ); }