Skip to main content

framework_tool_tui/
event.rs

1use std::time::Duration;
2
3use color_eyre::eyre::Report;
4use crossterm::event::EventStream;
5use futures::{FutureExt, StreamExt};
6use tokio::sync::{mpsc, watch};
7
8pub enum Event {
9    Tick,
10    Input(crossterm::event::Event),
11}
12
13pub struct EventLoop {
14    tx: mpsc::UnboundedSender<Event>,
15    rx: mpsc::UnboundedReceiver<Event>,
16    interval_tx: watch::Sender<Duration>,
17}
18
19impl Default for EventLoop {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl EventLoop {
26    pub fn new() -> Self {
27        let (tx, rx) = mpsc::unbounded_channel();
28        let (interval_tx, _interval_rx) = watch::channel(Duration::from_millis(1000));
29
30        Self {
31            tx,
32            rx,
33            interval_tx,
34        }
35    }
36
37    pub fn run(&self, tick_interval: Duration) {
38        let tx = self.tx.clone();
39        let mut interval_rx = self.interval_tx.subscribe();
40
41        tokio::spawn(async move {
42            let mut event_stream = EventStream::new();
43            let mut tick = tokio::time::interval(tick_interval);
44
45            loop {
46                let tick_event = tick.tick();
47                let input_event = event_stream.next().fuse();
48
49                tokio::select! {
50                    _ = tick_event => {
51                        let _ = tx.send(Event::Tick);
52                    }
53                    Some(Ok(event)) = input_event => {
54                        let _ = tx.send(Event::Input(event));
55                    }
56                    Ok(()) = interval_rx.changed() => {
57                        let new_interval = *interval_rx.borrow_and_update();
58                        tick = tokio::time::interval(new_interval);
59                    }
60                }
61            }
62        });
63    }
64
65    pub fn set_tick_interval(&self, tick_interval: Duration) {
66        let _ = self.interval_tx.send(tick_interval);
67    }
68
69    pub async fn next(&mut self) -> color_eyre::Result<Event> {
70        self.rx
71            .recv()
72            .await
73            .ok_or(Report::msg("Event loop async channel error"))
74    }
75}