use std::io;
use color_eyre::eyre::Result;
use crossterm::event::{Event, KeyCode};
use ratatui::Frame;
use ratatui::text::Text;
use tears::prelude::*;
use tears::subscription::{
terminal::TerminalEvents,
time::{Message as TimerMessage, Timer},
};
#[derive(Debug)]
enum Message {
Timer(TimerMessage),
Terminal(crossterm::event::Event),
TerminalError(io::Error),
}
#[derive(Debug, Default)]
struct Counter {
count: u32,
}
impl Application for Counter {
type Message = Message;
type Flags = ();
fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
(Self::default(), Command::none())
}
fn update(&mut self, msg: Self::Message) -> Command<Self::Message> {
match msg {
Message::Timer(TimerMessage::Tick) => {
self.count += 1;
Command::none()
}
Message::Terminal(event) => {
if let Event::Key(key) = event {
if key.code == KeyCode::Char('q') {
return Command::effect(Action::Quit);
}
}
Command::none()
}
Message::TerminalError(e) => {
eprintln!("Terminal error: {e}");
Command::effect(Action::Quit)
}
}
}
fn view(&self, frame: &mut Frame<'_>) {
let text = Text::raw(format!("Count: {} (Press 'q' to quit)", self.count));
frame.render_widget(text, frame.area());
}
fn subscriptions(&self) -> Vec<Subscription<Self::Message>> {
vec![
Subscription::new(Timer::new(1000)).map(Message::Timer),
Subscription::new(TerminalEvents::new()).map(|result| match result {
Ok(event) => Message::Terminal(event),
Err(e) => Message::TerminalError(e),
}),
]
}
}
#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
let mut terminal = ratatui::init();
let runtime = Runtime::<Counter>::new((), 60);
let result = runtime.run(&mut terminal).await;
ratatui::restore();
result?;
Ok(())
}