diff --git a/Cargo.lock b/Cargo.lock index acd3407..ba36d4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,6 +233,7 @@ checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ "bitflags", "crossterm_winapi", + "futures-core", "mio", "parking_lot", "rustix", @@ -422,6 +423,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -429,6 +445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -437,6 +454,34 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -455,10 +500,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -979,6 +1030,7 @@ dependencies = [ "color-eyre", "crossterm", "dirs", + "futures", "itunesdb", "ratatui", "regex", @@ -987,6 +1039,7 @@ dependencies = [ "serde_json", "soundcloud", "strum 0.27.0", + "throbber-widgets-tui", "tokio", "tokio-util", "toml", @@ -1816,6 +1869,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "throbber-widgets-tui" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d36b5738d666a2b4c91b7c24998a8588db724b3107258343ebf8824bf55b06d" +dependencies = [ + "rand", + "ratatui", +] + [[package]] name = "time" version = "0.3.37" diff --git a/Cargo.toml b/Cargo.toml index 0acf425..12ecfa1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,11 @@ serde_json = "1.0" regex = "1.11.1" ratatui = { version = "0.29.0", features = ["all-widgets"] } color-eyre = "0.6.3" -crossterm = "0.28.1" +crossterm = { version = "0.28.1", features = ["event-stream"] } +futures = "0.3" tokio = { version = "1", features = ["full"] } tokio-util = { version = "0.7.12", features = ["codec"] } strum = { version = "0.27", features = ["derive"] } soundcloud = { version = "0.1.4", git = "https://gitea.awain.net/alterwain/soundcloud_api.git" } -itunesdb = { version = "0.1.1", git = "https://gitea.awain.net/alterwain/ITunesDB.git" } \ No newline at end of file +itunesdb = { version = "0.1.1", git = "https://gitea.awain.net/alterwain/ITunesDB.git" } +throbber-widgets-tui = "0.8.0" diff --git a/src/main.rs b/src/main.rs index 6f5432d..68330b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ use std::{any::Any, cell::RefCell, collections::HashMap, error::Error, io, ops::Deref, path::{Path, PathBuf}}; use color_eyre::Result; -use crossterm::{event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEvent, KeyEventKind}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}}; +use crossterm::{event::{self, DisableMouseCapture, EnableMouseCapture, Event, EventStream, KeyCode, KeyEvent, KeyEventKind}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}}; +use futures::StreamExt; use ratatui::{buffer::Buffer, layout::{Layout, Rect}, prelude::{Backend, CrosstermBackend}, style::{Color, Stylize}, symbols::border, text::{Line, Text}, widgets::{Block, Paragraph, Tabs, Widget}, DefaultTerminal, Frame, Terminal}; use main_screen::MainScreen; use screen::AppScreen; @@ -52,10 +53,11 @@ impl Default for App { } impl App { - pub fn run(&mut self, terminal: &mut Terminal) -> io::Result<()> { + pub async fn run(&mut self, terminal: &mut Terminal) -> io::Result<()> { + let mut reader = EventStream::new(); while !self.token.is_cancelled() { + let _ = self.handle_events(&mut reader).await; terminal.draw(|frame| self.draw(frame))?; - self.handle_events()?; } Ok(()) } @@ -64,40 +66,43 @@ impl App { self.screens.get(&self.state).unwrap().render(frame); } - fn handle_events(&mut self) -> io::Result<()> { - if let Ok(event) = self.receiver.try_recv() { - match event { - AppEvent::IPodFound(path) => { - self.state = AppState::MainScreen; - let _ = self.sender.send(AppEvent::ParseItunes(path)); - }, - AppEvent::IPodNotFound => { - let _ = self.sender.send(AppEvent::SearchIPod); - }, - AppEvent::ITunesParsed(xdb) => { - - }, - AppEvent::SoundcloudGot(playlists) => { - let a = self.screens.get_mut(&AppState::MainScreen).unwrap(); - let screen: &mut MainScreen = a.as_any().downcast_mut::().unwrap(); - screen.soundcloud = Some(playlists); - }, - AppEvent::OverallProgress((c, max)) => { - let a = self.screens.get_mut(&AppState::MainScreen).unwrap(); - let screen: &mut MainScreen = a.as_any().downcast_mut::().unwrap(); - screen.progress = Some((c, max)); - screen.download_screen(); + async fn handle_events(&mut self, reader: &mut EventStream) { + tokio::select! { + Some(Ok(event)) = reader.next() => { + match event { + Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { + self.handle_key_event(key_event); + } + _ => {} + } + }, + Some(event) = self.receiver.recv() => { + match event { + AppEvent::IPodFound(path) => { + self.state = AppState::MainScreen; + let _ = self.sender.send(AppEvent::ParseItunes(path)); + }, + AppEvent::IPodNotFound => { + let _ = self.sender.send(AppEvent::SearchIPod); + }, + AppEvent::ITunesParsed(xdb) => { + + }, + AppEvent::SoundcloudGot(playlists) => { + let a = self.screens.get_mut(&AppState::MainScreen).unwrap(); + let screen: &mut MainScreen = a.as_any().downcast_mut::().unwrap(); + screen.soundcloud = Some(playlists); + }, + AppEvent::OverallProgress((c, max)) => { + let a = self.screens.get_mut(&AppState::MainScreen).unwrap(); + let screen: &mut MainScreen = a.as_any().downcast_mut::().unwrap(); + screen.progress = Some((c, max)); + screen.download_screen(); + } + _ => {} } - _ => {} } - }; - match event::read()? { - Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { - self.handle_key_event(key_event) - } - _ => {} - }; - Ok(()) + } } fn handle_key_event(&mut self, key_event: KeyEvent) { @@ -123,7 +128,7 @@ async fn main() -> Result<(), Box> { // create app and run it let mut app = App::default(); - app.run(&mut terminal); + let _ = app.run(&mut terminal).await; // restore terminal disable_raw_mode()?;