ratapp 0.6.0

A tiny framework to build multi-screen async applications with ratatui.
Documentation
use ratapp::{App, Navigator, Screen, Screens, State};
use ratatui::{
    Frame,
    crossterm::event::{Event, KeyCode},
    text::Text,
};
use std::time::Duration;
use tokio::task::JoinHandle;

#[tokio::main]
async fn main() {
    let mut app = App::new();

    app.run::<AppScreens>().await.unwrap();
}

#[derive(Screens)]
enum AppScreens {
    Home(TickBasedScreen),
}

impl Default for AppScreens {
    fn default() -> Self {
        AppScreens::Home(TickBasedScreen::default())
    }
}

fn get_tick(tick: usize) -> char {
    match tick % 4 {
        0 => '-',
        1 => '\\',
        2 => '|',
        3 => '/',
        _ => unreachable!(),
    }
}

#[derive(Default)]
struct TickBasedScreen {
    tick: State<usize>,
    ticker: Option<JoinHandle<()>>,
}

impl Screen<ScreenID> for TickBasedScreen {
    fn draw(&mut self, frame: &mut Frame) {
        let text = Text::from(format!(
            "{} Dummy loading... (press Q to exit)",
            get_tick(*self.tick.get())
        ));

        frame.render_widget(text, frame.area());
    }

    async fn on_event(&mut self, event: Event, navigator: Navigator<ScreenID>) {
        if let Event::Key(key_event) = event
            && key_event.code == KeyCode::Char('q')
        {
            navigator.exit();
        }
    }

    async fn on_enter(&mut self, navigator: Navigator<ScreenID>) {
        let tick = self.tick.clone();

        self.ticker = Some(tokio::spawn(async move {
            loop {
                tokio::time::sleep(Duration::from_millis(200)).await;
                *tick.get() += 1;
                navigator.rerender();
            }
        }));
    }

    async fn on_exit(&mut self, _navigator: Navigator<ScreenID>) {
        if let Some(ticker) = self.ticker.take() {
            ticker.abort();
        }
    }

    async fn on_resume(&mut self, navigator: Navigator<ScreenID>) {
        self.on_enter(navigator).await;
    }

    async fn on_pause(&mut self, navigator: Navigator<ScreenID>) {
        self.on_exit(navigator).await;
    }
}