p2p_chat/ui/terminal/
events.rs

1//! This module handles UI events for the `TerminalUI`.
2use anyhow::Result;
3use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
4
5use crate::ui::{UIAction, UIEvent, UIMode};
6
7use super::TerminalUI;
8
9impl TerminalUI {
10    /// Handles an incoming `UIEvent`, updating the UI state accordingly.
11    ///
12    /// This function processes various types of events such as new messages,
13    /// log batches, key presses, and terminal resizes.
14    ///
15    /// # Arguments
16    ///
17    /// * `event` - The `UIEvent` to handle.
18    ///
19    /// # Errors
20    ///
21    /// Returns an error if handling a key event fails.
22    pub(super) async fn handle_event(&mut self, event: UIEvent) -> Result<()> {
23        match event {
24            UIEvent::NewMessage(msg) => {
25                self.state.add_message(msg);
26            }
27            UIEvent::ChatMessage(msg) => {
28                self.state.add_chat_message(msg);
29            }
30            UIEvent::HistoryOutput(msg) => {
31                self.state.add_history_output(msg);
32            }
33            UIEvent::NewLogBatch(entries) => {
34                self.state.add_log_batch(entries);
35            }
36            UIEvent::RefreshLogs => {
37                self.state.refresh_logs();
38            }
39            UIEvent::KeyPress(key_event) => {
40                self.handle_key_event(key_event).await?;
41            }
42            UIEvent::Resize(width, height) => {
43                self.state.terminal_size = (width, height);
44            }
45            UIEvent::UpdatePeersCount(count) => {
46                self.state.connected_peers_count = count;
47            }
48            UIEvent::UpdateDiscoveredPeers(peers) => {
49                self.update_discovered_peers(peers);
50            }
51        }
52        Ok(())
53    }
54
55    /// Handles a keyboard `KeyEvent`.
56    ///
57    /// This function processes key presses, handling special key combinations
58    /// for mode switching or exiting the application, and then delegates
59    /// regular key presses to the current UI mode's handler.
60    ///
61    /// # Arguments
62    ///
63    /// * `key` - The `KeyEvent` to handle.
64    ///
65    /// # Errors
66    ///
67    /// Returns an error if the current UI mode's key handler fails.
68    async fn handle_key_event(&mut self, key: KeyEvent) -> Result<()> {
69        match (key.code, key.modifiers) {
70            (KeyCode::F(9), _) => {
71                self.state.toggle_mode();
72                if let Some(ref log_buffer) = self.log_buffer {
73                    log_buffer.set_ui_mode(self.state.mode.clone());
74                    if let UIMode::Logs { level, .. } = &self.state.mode {
75                        log_buffer.set_display_level(*level);
76                    }
77                }
78                return Ok(());
79            }
80            (KeyCode::Char('c'), KeyModifiers::CONTROL) => {
81                let _ = self.action_tx.send(UIAction::Exit);
82                return Ok(());
83            }
84            (KeyCode::Char('l'), KeyModifiers::CONTROL) => {
85                self.state.toggle_mode();
86                if let Some(ref log_buffer) = self.log_buffer {
87                    log_buffer.set_ui_mode(self.state.mode.clone());
88                    if let UIMode::Logs { level, .. } = &self.state.mode {
89                        log_buffer.set_display_level(*level);
90                    }
91                }
92                return Ok(());
93            }
94            _ => {}
95        }
96
97        let old_mode = self.state.mode.clone();
98        match &self.state.mode {
99            UIMode::Chat => {
100                self.chat_mode
101                    .handle_key(&mut self.state, key, &self.action_tx)
102                    .await?;
103            }
104            UIMode::Logs { .. } => {
105                self.log_mode
106                    .handle_key(&mut self.state, key, &self.action_tx)
107                    .await?;
108
109                if let (
110                    UIMode::Logs {
111                        level: old_level, ..
112                    },
113                    UIMode::Logs {
114                        level: new_level, ..
115                    },
116                ) = (&old_mode, &self.state.mode)
117                {
118                    if old_level != new_level {
119                        if let Some(ref log_buffer) = self.log_buffer {
120                            log_buffer.set_display_level(*new_level);
121                        }
122                    }
123                }
124            }
125        }
126
127        Ok(())
128    }
129}