use color_eyre::eyre::OptionExt;
use crossterm::event::Event as CrosstermEvent;
use futures::{FutureExt, StreamExt};
use palo_core::events::Event as CoreEvent;
use std::time::Duration;
use tokio::sync::broadcast;
use tokio::sync::mpsc;
const TICK_FPS: f64 = 30.0;
#[derive(Clone, Debug)]
pub enum Event {
Tick,
Crossterm(CrosstermEvent),
App(AppEvent),
Core(CoreEvent),
}
#[derive(Clone, Debug)]
pub enum AppEvent {
Quit,
}
#[derive(Debug)]
pub struct EventHandler {
sender: mpsc::UnboundedSender<Event>,
receiver: mpsc::UnboundedReceiver<Event>,
}
impl EventHandler {
pub fn new() -> Self {
Self::with_core_events(None)
}
pub fn with_core_events(core_events: Option<broadcast::Receiver<CoreEvent>>) -> Self {
let (sender, receiver) = mpsc::unbounded_channel();
let actor = EventTask::new(sender.clone(), core_events);
tokio::spawn(async { actor.run().await });
Self { sender, receiver }
}
pub async fn next(&mut self) -> color_eyre::Result<Event> {
self.receiver
.recv()
.await
.ok_or_eyre("Failed to receive event")
}
pub fn send(&mut self, app_event: AppEvent) {
let _ = self.sender.send(Event::App(app_event));
}
}
impl Default for EventHandler {
fn default() -> Self {
Self::new()
}
}
struct EventTask {
sender: mpsc::UnboundedSender<Event>,
core_events: Option<broadcast::Receiver<CoreEvent>>,
}
impl EventTask {
fn new(
sender: mpsc::UnboundedSender<Event>,
core_events: Option<broadcast::Receiver<CoreEvent>>,
) -> Self {
Self {
sender,
core_events,
}
}
async fn run(mut self) -> color_eyre::Result<()> {
let tick_rate = Duration::from_secs_f64(1.0 / TICK_FPS);
let mut reader = crossterm::event::EventStream::new();
let mut tick = tokio::time::interval(tick_rate);
loop {
let tick_delay = tick.tick();
let crossterm_event = reader.next().fuse();
let core_event = async {
match self.core_events.as_mut() {
Some(receiver) => receiver.recv().await.ok(),
None => None,
}
}
.fuse();
tokio::select! {
_ = self.sender.closed() => {
break;
}
_ = tick_delay => {
self.send(Event::Tick);
}
Some(Ok(evt)) = crossterm_event => {
self.send(Event::Crossterm(evt));
}
core = core_event => {
if let Some(event) = core {
self.send(Event::Core(event));
}
}
};
}
Ok(())
}
fn send(&self, event: Event) {
let _ = self.sender.send(event);
}
}