Skip to main content

romm_cli/tui/app/
run.rs

1//! Main TUI event loop.
2
3use anyhow::Result;
4
5use crate::tui::runtime::{LoopControl, RuntimeOptions, TuiSession};
6
7use super::event::{Action, AppEvent};
8use super::App;
9
10impl App {
11    pub async fn run(&mut self) -> Result<()> {
12        self.open_library_browse();
13        let mut session = TuiSession::enter(RuntimeOptions::default())?;
14        let mut quit = false;
15
16        while !quit {
17            let events = self.poll_frame_events()?;
18            for event in events {
19                for action in self.map_event(event) {
20                    if self.update(action).await? {
21                        quit = true;
22                        break;
23                    }
24                }
25                if quit {
26                    break;
27                }
28            }
29
30            session.terminal_mut().draw(|f| self.render(f))?;
31
32            if self.on_frame_end().await? == LoopControl::Break {
33                quit = true;
34            }
35        }
36
37        session.leave()?;
38        Ok(())
39    }
40
41    fn poll_frame_events(&mut self) -> Result<Vec<AppEvent>> {
42        let mut events = self.drain_background_events();
43        if self
44            .startup_splash
45            .as_ref()
46            .is_some_and(|s| s.should_auto_dismiss())
47        {
48            events.push(AppEvent::AutoDismissSplash);
49        }
50
51        if self
52            .startup_update_prompt
53            .as_ref()
54            .is_some_and(|p| p.updating)
55        {
56            return Ok(events);
57        }
58
59        if crossterm::event::poll(std::time::Duration::from_millis(100))? {
60            match crossterm::event::read()? {
61                crossterm::event::Event::Key(key) => events.push(AppEvent::Key(key)),
62                crossterm::event::Event::Paste(text) => events.push(AppEvent::Paste(text)),
63                _ => {}
64            }
65        }
66        Ok(events)
67    }
68
69    async fn on_frame_end(&mut self) -> Result<LoopControl> {
70        if self
71            .startup_update_prompt
72            .as_ref()
73            .is_some_and(|p| p.updating)
74        {
75            self.update(Action::ApplyStartupUpdate).await?;
76            return Ok(LoopControl::Continue);
77        }
78        self.update(Action::ProcessDeferredRomLoad).await?;
79        Ok(LoopControl::Continue)
80    }
81}