use async_trait::async_trait;
use color_eyre::eyre::OptionExt;
use crossterm::{self, event::Event as CrosstermEvent};
use futures::StreamExt;
use std::time::Duration;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
use crate::app::app_event::AppEvent;
const TICK_FPS: f64 = 30.0;
#[derive(Clone, Debug)]
pub enum BasicEvent {
Tick,
Crossterm(CrosstermEvent),
App(AppEvent),
}
#[derive(Debug)]
pub struct EventHandler {
sender: UnboundedSender<BasicEvent>,
receiver: UnboundedReceiver<BasicEvent>,
}
#[async_trait]
pub trait BasicEventSenderExt {
async fn send_event<T: Into<BasicEvent> + Send>(&self, msg: T);
}
#[async_trait]
impl BasicEventSenderExt for UnboundedSender<BasicEvent> {
async fn send_event<T: Into<BasicEvent> + Send>(&self, msg: T) {
self.send(msg.into()).ok();
}
}
impl EventHandler {
pub fn new() -> Self {
let (sender, receiver) = tokio::sync::mpsc::unbounded_channel::<BasicEvent>();
let actor = EventTask::new(sender.clone());
tokio::spawn(async { actor.run().await }); Self { sender, receiver }
}
pub async fn next(&mut self) -> color_eyre::Result<BasicEvent> {
self.receiver
.recv()
.await
.ok_or_eyre("Failed to receive event")
}
pub fn send(&mut self, app_event: impl Into<BasicEvent>) {
self.sender.send(app_event.into()).ok();
}
pub fn send_app_event(&mut self, app_event: AppEvent) {
match app_event {
AppEvent::None => {}
_ => {
self.sender.send(app_event.into()).ok();
}
}
}
pub fn sender(&self) -> UnboundedSender<BasicEvent> {
self.sender.clone()
}
}
impl Default for EventHandler {
fn default() -> Self {
Self::new()
}
}
struct EventTask {
sender: UnboundedSender<BasicEvent>,
}
impl EventTask {
fn new(sender: UnboundedSender<BasicEvent>) -> Self {
Self { sender }
}
async fn run(mut self) -> color_eyre::Result<()> {
let tick_rate = Duration::from_secs_f64(1.0 / TICK_FPS);
let mut tick = tokio::time::interval(tick_rate);
let mut reader = crossterm::event::EventStream::new();
loop {
let tick_delay = tick.tick();
let crossterm_event = reader.next();
tokio::select! {
_ = self.sender.closed() => {
break;
}
_ = tick_delay => {
self.send(BasicEvent::Tick);
},
val = crossterm_event => {
if let Some(val) = val {
self.send(BasicEvent::Crossterm(val?));
}
},
};
}
Ok(())
}
fn send(&mut self, event: BasicEvent) {
self.sender.send(event).ok();
}
}