use std::thread;
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyModifiers};
use futures::future::FutureExt;
use tokio::{
sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
oneshot,
},
task::unconstrained,
};
#[derive(Debug, PartialEq)]
pub enum Command {
Info,
NextTrack,
PrevTrack,
Print(String),
Quit,
}
pub struct User {
tx_cmd: UnboundedSender<Command>,
tx_user: UnboundedSender<UserCommand>,
rx_user: UnboundedReceiver<UserCommand>,
}
#[derive(Clone)]
pub struct UserHandle {
pub tx_user: UnboundedSender<UserCommand>,
}
impl UserHandle {
pub async fn take_input(&self) -> UnboundedReceiver<KeyEvent> {
let (tx, rx) = oneshot::channel::<UnboundedReceiver<KeyEvent>>();
self.tx_user.send(UserCommand::TakeInput(tx)).unwrap();
rx.await.unwrap()
}
}
#[derive(Debug)]
pub enum UserCommand {
TakeInput(oneshot::Sender<UnboundedReceiver<KeyEvent>>),
}
impl User {
pub fn new(tx_cmd: UnboundedSender<Command>) -> Self {
let (tx_user, rx_user) = unbounded_channel::<UserCommand>();
Self {
tx_cmd,
tx_user,
rx_user,
}
}
pub fn get_handle(&self) -> UserHandle {
UserHandle {
tx_user: self.tx_user.clone(),
}
}
pub async fn run(self) {
let (tx, mut rx) = unbounded_channel::<Event>();
thread::spawn(move || loop {
while let Ok(event) = event::read() {
tx.send(event).unwrap();
}
});
let (tx_widget_stack, mut rx_widget_stack) = unbounded_channel();
let mut rx_user = self.rx_user;
tokio::spawn(async move {
while let Some(command) = rx_user.recv().await {
match command {
UserCommand::TakeInput(tx_oneshot) => {
let (tx, rx) = unbounded_channel();
tx_widget_stack.send(tx).unwrap();
tx_oneshot.send(rx).unwrap();
}
}
}
});
let mut widget_stack: Vec<UnboundedSender<KeyEvent>> = Vec::new();
while let Some(event) = rx.recv().await {
if let Some(Some(tx_widget)) = unconstrained(rx_widget_stack.recv()).now_or_never() {
widget_stack.push(tx_widget);
}
match event {
Event::Key(event) => match event.code {
KeyCode::Char(ch) => {
if !widget_stack.is_empty() {
match widget_stack[widget_stack.len() - 1].send(event) {
Ok(_) => continue,
Err(_) => {
widget_stack.pop();
}
}
}
match ch {
'c' => {
if event.modifiers == KeyModifiers::CONTROL {
self.tx_cmd.send(Command::Quit).unwrap();
}
}
'i' => {
self.tx_cmd.send(Command::Info).unwrap();
}
'q' => {
self.tx_cmd.send(Command::Quit).unwrap();
}
_ => {}
}
}
KeyCode::Esc => {
self.tx_cmd.send(Command::Quit).unwrap();
}
KeyCode::Left => {
self.tx_cmd.send(Command::PrevTrack).unwrap();
}
KeyCode::Right => {
self.tx_cmd.send(Command::NextTrack).unwrap();
}
_ => {}
},
Event::Mouse(_) => {}
Event::Resize(_, _) => {}
}
}
}
}