use color_eyre::eyre::{eyre, Result}; use crossterm::event::EventStream; use futures::FutureExt; use futures::StreamExt; use std::time::Duration; use tokio::sync::mpsc::UnboundedSender; use tokio::task::JoinHandle; #[derive(Clone)] pub(crate) enum AppEvent { Error, Tick, Raw(crossterm::event::Event), } pub(crate) struct EventHandler { _tx: UnboundedSender, rx: tokio::sync::mpsc::UnboundedReceiver, pub task: JoinHandle<()>, } impl EventHandler { pub fn new(tick_rate: Duration) -> Self { let mut interval = tokio::time::interval(tick_rate); let mut event_reader = EventStream::new(); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let _tx = tx.clone(); let task = tokio::spawn(async move { loop { let delay = interval.tick(); let crossterm_event = event_reader.next().fuse(); tokio::select! { maybe_event = crossterm_event => { if let Some(Err(_)) = maybe_event { tx.send(AppEvent::Error).unwrap() } else if let Some(Ok(event)) = maybe_event { tx.send(AppEvent::Raw(event)).unwrap(); } } _ = delay => { tx.send(AppEvent::Tick).unwrap() } } } }); Self { _tx, rx, task } } pub(crate) async fn next(&mut self) -> Result { self.rx.recv().await.ok_or(eyre!("Unable to get event")) } }