1use std::io::Stdout;
2use std::sync::mpsc::{self, TryRecvError};
3use std::sync::Arc;
4use std::thread;
5use std::time::Duration;
6
7use anyhow::Result;
8use parking_lot::Mutex;
9use ratatui::backend::CrosstermBackend;
10use ratatui::Terminal;
11
12use crate::app::Status;
13use crate::io::Display;
14use crate::log_info;
15
16pub struct Displayer {
21 tx: mpsc::Sender<()>,
22 handle: thread::JoinHandle<Result<()>>,
23}
24
25impl Displayer {
26 const THIRTY_PER_SECONDS_IN_MILLIS: u64 = 33;
27
28 pub fn new(term: Terminal<CrosstermBackend<Stdout>>, status: Arc<Mutex<Status>>) -> Self {
29 let (tx, rx) = mpsc::channel();
30 let mut display = Display::new(term);
31
32 let handle = thread::spawn(move || -> Result<()> {
33 loop {
34 match rx.try_recv() {
35 Ok(_) | Err(TryRecvError::Disconnected) => {
36 log_info!("terminating displayer");
37 display.restore_terminal()?;
38 drop(display);
39 break;
40 }
41 Err(TryRecvError::Empty) => {}
42 }
43 let mut status = status.lock();
44 if !status.internal_settings.is_disabled() {
45 display.display_all(&status);
46 }
47 if status.should_tabs_images_be_cleared() {
48 status.set_tabs_images_cleared();
49 }
50 if status.should_be_cleared() {
51 status.internal_settings.reset_clear()
52 }
53 drop(status);
54
55 thread::sleep(Duration::from_millis(Self::THIRTY_PER_SECONDS_IN_MILLIS));
56 }
57 Ok(())
58 });
59 Self { tx, handle }
60 }
61
62 pub fn quit(self) {
63 log_info!("stopping display loop");
64 match self.tx.send(()) {
65 Ok(()) => (),
66 Err(e) => log_info!("Displayer::quit error {e:?}"),
67 };
68 let _ = self.handle.join();
69 }
70}