multiverse/widgets/
status.rs1use std::{
2 sync::{
3 Arc,
4 mpsc::{self, Receiver},
5 },
6 time::Duration,
7};
8
9use matrix_sdk_common::locks::Mutex;
10use ratatui::{
11 prelude::{Buffer, Rect, *},
12 widgets::Paragraph,
13};
14use tokio::{
15 spawn,
16 task::{JoinHandle, spawn_blocking},
17 time::sleep,
18};
19
20use crate::{AppState, GlobalMode};
21
22const MESSAGE_DURATION: Duration = Duration::from_secs(4);
23
24pub struct Status {
25 last_status_message: Arc<Mutex<Option<String>>>,
27
28 message_sender: mpsc::Sender<String>,
31
32 _receiver_task: JoinHandle<()>,
35}
36
37impl Default for Status {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43#[derive(Clone)]
46pub struct StatusHandle {
47 message_sender: mpsc::Sender<String>,
48}
49
50impl StatusHandle {
51 pub fn set_message(&self, status: String) {
54 self.message_sender.send(status).expect(
55 "We should be able to send the status message since the receiver is alive \
56 as long as we are alive",
57 );
58 }
59}
60
61impl Status {
62 pub fn new() -> Self {
64 let (message_sender, receiver) = mpsc::channel();
65 let last_status_message = Arc::new(Mutex::new(None));
66
67 let receiver_task = spawn_blocking({
68 let last_status_message = last_status_message.clone();
69 move || Self::receiving_task(receiver, last_status_message)
70 });
71
72 Self { last_status_message, _receiver_task: receiver_task, message_sender }
73 }
74
75 fn receiving_task(receiver: Receiver<String>, status_message: Arc<Mutex<Option<String>>>) {
76 let mut clear_message_task: Option<JoinHandle<()>> = None;
77
78 while let Ok(message) = receiver.recv() {
79 if let Some(task) = clear_message_task.take() {
80 task.abort();
81 }
82
83 {
84 let mut status_message = status_message.lock();
85 *status_message = Some(message);
86 }
87
88 clear_message_task = Some(spawn({
89 let status_message = status_message.clone();
90
91 async move {
92 sleep(MESSAGE_DURATION).await;
94 status_message.lock().take();
95 }
96 }));
97 }
98 }
99
100 pub fn set_message(&self, status: String) {
103 self.message_sender.send(status).expect(
104 "We should be able to send the status message since the receiver is alive \
105 as long as we are alive",
106 );
107 }
108
109 pub fn handle(&self) -> StatusHandle {
112 StatusHandle { message_sender: self.message_sender.clone() }
113 }
114}
115
116impl StatefulWidget for &mut Status {
117 type State = AppState;
118
119 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
122 let status_message = self.last_status_message.lock();
123
124 let content = if let Some(status_message) = status_message.as_deref() {
125 status_message
126 } else {
127 let AppState { global_mode, throbber_state: _ } = state;
128
129 match global_mode {
130 GlobalMode::Help => "Press q to exit the help screen",
131 GlobalMode::Settings { .. } => "Press ESC to exit the settings screen",
132 GlobalMode::CreateRoom { .. } => "Press ESC to exit the create room screen",
133 GlobalMode::Searching { .. } => "Press ESC to exit the search screen",
134 GlobalMode::Default => "Press F1 to show the help screen",
135 GlobalMode::Exiting { .. } => "",
136 }
137 };
138
139 Paragraph::new(content).centered().render(area, buf);
140 }
141}