1use std::{sync::Arc, time::Duration};
2
3use crossterm::event::{Event as CrosstermEvent, KeyEvent, KeyEventKind, MouseEvent};
4use futures::{FutureExt, StreamExt};
5use tokio::{
6 sync::{mpsc, Mutex},
7 task::JoinHandle,
8};
9use tokio_util::sync::CancellationToken;
10
11use crate::{
12 action::Action,
13 components::{home::Home, Component},
14};
15
16#[derive(Clone, Copy, Debug)]
17pub enum Event {
18 Quit,
19 Error,
20 Closed,
21 RenderTick,
22 RefreshTick,
23 Key(KeyEvent),
24 Mouse(MouseEvent),
25 Resize(u16, u16),
26}
27
28pub struct EventHandler {
29 pub task: JoinHandle<()>,
30 cancellation_token: CancellationToken,
31}
32
33const SERVICE_REFRESH_INTERVAL_MS: u64 = 5000;
34
35impl EventHandler {
36 pub fn new(home: Arc<Mutex<Home>>, action_tx: mpsc::UnboundedSender<Action>) -> Self {
37 let (event_tx, mut event_rx) = mpsc::unbounded_channel();
38 let cancellation_token = CancellationToken::new();
39 let _cancellation_token = cancellation_token.clone();
40 let task = tokio::spawn(async move {
41 let mut reader = crossterm::event::EventStream::new();
42 let mut refresh_services_interval = tokio::time::interval(Duration::from_millis(SERVICE_REFRESH_INTERVAL_MS));
43 refresh_services_interval.tick().await;
44 loop {
45 let refresh_delay = refresh_services_interval.tick();
46 let crossterm_event = reader.next().fuse();
47 tokio::select! {
48 _ = _cancellation_token.cancelled() => {
49 break;
50 }
51 maybe_event = crossterm_event => {
52 match maybe_event {
53 Some(Ok(evt)) => {
54 match evt {
55 CrosstermEvent::Key(key) => {
56 if key.kind == KeyEventKind::Press {
57 event_tx.send(Event::Key(key)).unwrap();
58 }
59 },
60 CrosstermEvent::Resize(x, y) => {
62 event_tx.send(Event::Resize(x, y)).unwrap();
63 },
64 _ => {},
65 }
66 }
67 Some(Err(_)) => {
68 event_tx.send(Event::Error).unwrap();
69 }
70 None => {},
71 }
72 },
73 _ = refresh_delay => {
74 event_tx.send(Event::RefreshTick).unwrap();
75 },
76 event = event_rx.recv() => {
77 let actions = home.lock().await.handle_events(event);
78 for action in actions {
79 action_tx.send(action).unwrap();
80 }
81 }
82 }
83 }
84 });
85 Self { task, cancellation_token }
86 }
87
88 pub fn stop(&mut self) {
89 self.cancellation_token.cancel();
90 }
91}