eazygit 0.5.1

A fast TUI for Git with staging, conflicts, rebase, and palette-first UX
Documentation
//! Notification system for user feedback.
//!
//! Manages notifications with different severity levels,
//! auto-dismissal timers, and stacking behavior.

use std::time::{Duration, Instant};
use std::collections::VecDeque;

/// Notification severity.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NotificationLevel {
    /// Informational message
    Info,
    /// Success message
    Success,
    /// Warning message
    Warning,
    /// Error message
    Error,
}

/// A notification to display to the user.
#[derive(Debug, Clone)]
pub struct Notification {
    /// Unique ID
    pub id: u64,
    /// Message text
    pub message: String,
    /// Severity level
    pub level: NotificationLevel,
    /// When the notification was created
    pub created_at: Instant,
    /// How long to display (None = until dismissed)
    pub duration: Option<Duration>,
}

impl Notification {
    /// Check if this notification has expired.
    pub fn is_expired(&self) -> bool {
        if let Some(duration) = self.duration {
            self.created_at.elapsed() >= duration
        } else {
            false
        }
    }
}

/// Notification manager.
pub struct NotificationManager {
    /// Active notifications
    notifications: VecDeque<Notification>,
    /// Max concurrent notifications
    max_visible: usize,
    /// Next ID
    next_id: u64,
}

impl NotificationManager {
    /// Create a new notification manager.
    pub fn new(max_visible: usize) -> Self {
        Self {
            notifications: VecDeque::new(),
            max_visible,
            next_id: 0,
        }
    }
    
    /// Show a notification.
    pub fn notify(
        &mut self,
        message: impl Into<String>,
        level: NotificationLevel,
        duration: Option<Duration>,
    ) -> u64 {
        let id = self.next_id;
        self.next_id += 1;
        
        let notification = Notification {
            id,
            message: message.into(),
            level,
            created_at: Instant::now(),
            duration,
        };
        
        // Evict oldest if at capacity
        while self.notifications.len() >= self.max_visible {
            self.notifications.pop_front();
        }
        
        self.notifications.push_back(notification);
        id
    }
    
    /// Show info notification (auto-dismiss after 3s).
    pub fn info(&mut self, message: impl Into<String>) -> u64 {
        self.notify(message, NotificationLevel::Info, Some(Duration::from_secs(3)))
    }
    
    /// Show success notification (auto-dismiss after 3s).
    pub fn success(&mut self, message: impl Into<String>) -> u64 {
        self.notify(message, NotificationLevel::Success, Some(Duration::from_secs(3)))
    }
    
    /// Show warning notification (auto-dismiss after 5s).
    pub fn warning(&mut self, message: impl Into<String>) -> u64 {
        self.notify(message, NotificationLevel::Warning, Some(Duration::from_secs(5)))
    }
    
    /// Show error notification (must be dismissed manually).
    pub fn error(&mut self, message: impl Into<String>) -> u64 {
        self.notify(message, NotificationLevel::Error, None)
    }
    
    /// Dismiss a notification by ID.
    pub fn dismiss(&mut self, id: u64) {
        self.notifications.retain(|n| n.id != id);
    }
    
    /// Dismiss all notifications.
    pub fn dismiss_all(&mut self) {
        self.notifications.clear();
    }
    
    /// Remove expired notifications.
    pub fn cleanup_expired(&mut self) {
        self.notifications.retain(|n| !n.is_expired());
    }
    
    /// Get visible notifications.
    pub fn visible(&self) -> impl Iterator<Item = &Notification> {
        self.notifications.iter()
    }
    
    /// Get notification count.
    pub fn count(&self) -> usize {
        self.notifications.len()
    }
}

impl Default for NotificationManager {
    fn default() -> Self {
        Self::new(3) // Show max 3 at a time
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_notification_lifecycle() {
        let mut nm = NotificationManager::new(5);
        
        let id = nm.info("Test message");
        assert_eq!(nm.count(), 1);
        
        nm.dismiss(id);
        assert_eq!(nm.count(), 0);
    }
    
    #[test]
    fn test_notification_levels() {
        let mut nm = NotificationManager::new(5);
        
        nm.info("info");
        nm.success("success");
        nm.warning("warning");
        nm.error("error");
        
        assert_eq!(nm.count(), 4);
    }
}