1use std::io::stdout;
2use std::sync::Arc;
3use std::time::Duration;
4
5use app::{App, AppReturn};
6use eyre::Result;
7use inputs::events::Events;
8use inputs::InputEvent;
9use io::IoEvent;
10use tui::backend::CrosstermBackend;
11use tui::Terminal;
12
13use crate::app::ui;
14
15pub mod app;
16pub mod inputs;
17pub mod io;
18
19pub async fn start_ui(app: &Arc<tokio::sync::Mutex<App>>) -> Result<()> {
20 let mut stdout = stdout();
22 crossterm::terminal::enable_raw_mode()?;
23 crossterm::execute!(
24 stdout,
25 crossterm::terminal::EnterAlternateScreen,
26 crossterm::event::EnableMouseCapture
27 )?;
28 let backend = CrosstermBackend::new(stdout);
29 let mut terminal = Terminal::new(backend)?;
30 terminal.clear()?;
31 terminal.hide_cursor()?;
32
33 let tick_rate = Duration::from_millis(200);
35 let mut events = Events::new(tick_rate);
36
37 {
39 let mut app = app.lock().await;
40 app.dispatch(IoEvent::Initialize).await;
41 }
42
43 loop {
44 let mut app = app.lock().await;
45
46 terminal.draw(|rect| ui::draw(rect, &mut app))?;
48
49 let result = match events.next().await {
51 InputEvent::Input(key) => app.do_action(key).await,
52 InputEvent::Tick => app.update_on_tick().await,
53 };
54 if result == AppReturn::Exit {
56 events.close();
57 break;
58 }
59 }
60
61 terminal.show_cursor()?;
64 crossterm::execute!(
65 terminal.backend_mut(),
66 crossterm::terminal::LeaveAlternateScreen,
67 crossterm::event::DisableMouseCapture
68 )?;
69 crossterm::terminal::disable_raw_mode()?;
70
71 Ok(())
72}