Skip to main content

metis_docs_tui/models/
message.rs

1use std::time::{Duration, Instant};
2
3/// Type of message to display
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum MessageType {
6    Error,
7    Success,
8    Warning,
9    Info,
10}
11
12impl MessageType {
13    /// Get the display duration for this message type
14    pub fn duration(&self) -> Duration {
15        match self {
16            MessageType::Error => Duration::from_secs(10),
17            MessageType::Success => Duration::from_secs(5),
18            MessageType::Warning => Duration::from_secs(7),
19            MessageType::Info => Duration::from_secs(4),
20        }
21    }
22
23    /// Get the display prefix for this message type
24    pub fn prefix(&self) -> &'static str {
25        match self {
26            MessageType::Error => "ERROR",
27            MessageType::Success => "SUCCESS",
28            MessageType::Warning => "WARNING",
29            MessageType::Info => "INFO",
30        }
31    }
32}
33
34/// A message to display to the user
35#[derive(Debug, Clone)]
36pub struct Message {
37    pub id: u64,
38    pub message_type: MessageType,
39    pub content: String,
40    pub created_at: Instant,
41    pub auto_clear: bool,
42}
43
44impl Message {
45    /// Create a new message
46    pub fn new(id: u64, message_type: MessageType, content: String) -> Self {
47        Self {
48            id,
49            message_type,
50            content,
51            created_at: Instant::now(),
52            auto_clear: true,
53        }
54    }
55
56    /// Create a message that won't auto-clear
57    pub fn persistent(id: u64, message_type: MessageType, content: String) -> Self {
58        Self {
59            id,
60            message_type,
61            content,
62            created_at: Instant::now(),
63            auto_clear: false,
64        }
65    }
66
67    /// Check if this message should be cleared based on its age
68    pub fn should_clear(&self) -> bool {
69        if !self.auto_clear {
70            return false;
71        }
72
73        let age = self.created_at.elapsed();
74        age >= self.message_type.duration()
75    }
76
77    /// Get display text for the message
78    pub fn display_text(&self) -> String {
79        format!("{}: {}", self.message_type.prefix(), self.content)
80    }
81}
82
83/// State container for messages
84#[derive(Debug)]
85pub struct MessageState {
86    pub current_message: Option<Message>,
87    next_id: u64,
88}
89
90impl Default for MessageState {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96impl MessageState {
97    /// Create a new message state
98    pub fn new() -> Self {
99        Self {
100            current_message: None,
101            next_id: 1,
102        }
103    }
104
105    /// Set the current message (replaces any existing message)
106    fn set_message(&mut self, message_type: MessageType, content: String) -> u64 {
107        let id = self.next_id;
108        self.next_id += 1;
109
110        let message = Message::new(id, message_type, content);
111        self.current_message = Some(message);
112
113        id
114    }
115
116    /// Add an error message
117    pub fn add_error(&mut self, content: String) -> u64 {
118        self.set_message(MessageType::Error, content)
119    }
120
121    /// Add a success message
122    pub fn add_success(&mut self, content: String) -> u64 {
123        self.set_message(MessageType::Success, content)
124    }
125
126    /// Add a warning message
127    pub fn add_warning(&mut self, content: String) -> u64 {
128        self.set_message(MessageType::Warning, content)
129    }
130
131    /// Add an info message
132    pub fn add_info(&mut self, content: String) -> u64 {
133        self.set_message(MessageType::Info, content)
134    }
135
136    /// Clear the current message
137    pub fn clear_message(&mut self) {
138        self.current_message = None;
139    }
140
141    /// Clear expired messages
142    pub fn clear_expired_messages(&mut self) {
143        if let Some(ref msg) = self.current_message {
144            if msg.should_clear() {
145                self.current_message = None;
146            }
147        }
148    }
149
150    /// Get the current message if it's not expired
151    pub fn get_current_message(&self) -> Option<&Message> {
152        self.current_message
153            .as_ref()
154            .filter(|msg| !msg.should_clear())
155    }
156
157    /// Check if there is an active message
158    pub fn has_messages(&self) -> bool {
159        self.get_current_message().is_some()
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_message_creation() {
169        let msg = Message::new(1, MessageType::Error, "Test error".to_string());
170        assert_eq!(msg.id, 1);
171        assert_eq!(msg.message_type, MessageType::Error);
172        assert_eq!(msg.content, "Test error");
173        assert!(msg.auto_clear);
174    }
175
176    #[test]
177    fn test_persistent_message() {
178        let msg = Message::persistent(1, MessageType::Info, "Persistent info".to_string());
179        assert!(!msg.auto_clear);
180        assert!(!msg.should_clear());
181    }
182
183    #[test]
184    fn test_message_display_text() {
185        let msg = Message::new(1, MessageType::Success, "Operation completed".to_string());
186        assert_eq!(msg.display_text(), "SUCCESS: Operation completed");
187    }
188
189    #[test]
190    fn test_message_state_operations() {
191        let mut state = MessageState::new();
192
193        // Initially no message
194        assert!(!state.has_messages());
195
196        // Add error message
197        state.add_error("Error 1".to_string());
198        assert!(state.has_messages());
199
200        // Add success message (replaces error)
201        state.add_success("Success 1".to_string());
202        assert!(state.has_messages());
203        if let Some(msg) = state.get_current_message() {
204            assert_eq!(msg.message_type, MessageType::Success);
205            assert_eq!(msg.content, "Success 1");
206        }
207
208        // Clear message
209        state.clear_message();
210        assert!(!state.has_messages());
211    }
212}