diff --git a/src/audio/waiter.rs b/src/audio/waiter.rs index 7124484..d6a4e57 100644 --- a/src/audio/waiter.rs +++ b/src/audio/waiter.rs @@ -2,39 +2,35 @@ use std::{sync::Arc, thread::sleep, time::Duration}; use rodio::Sink; use tokio::{ - sync::{broadcast, mpsc}, + sync::{mpsc, Notify}, task::{self, JoinHandle}, }; -use crate::ui::{self, Update}; - pub struct Handle { _task: JoinHandle<()>, + notify: Arc, } impl Handle { - pub fn new( - sink: Arc, - tx: mpsc::Sender, - rx: broadcast::Receiver, - ) -> Self { + pub fn new(sink: Arc, tx: mpsc::Sender) -> Self { + let notify = Arc::new(Notify::new()); + Self { - _task: task::spawn_blocking(|| Self::waiter(sink, tx, rx)), + _task: task::spawn(Self::waiter(sink, tx, notify.clone())), + notify, } } - fn waiter( - sink: Arc, - tx: mpsc::Sender, - mut rx: broadcast::Receiver, - ) { + pub fn notify(&self) { + self.notify.notify_one(); + } + + async fn waiter(sink: Arc, tx: mpsc::Sender, notify: Arc) { 'main: loop { - if !matches!(rx.blocking_recv(), Ok(Update::Track(_))) { - continue; - } + notify.notified().await; while !sink.empty() { - if matches!(rx.try_recv(), Ok(Update::Quit)) { + if Arc::strong_count(¬ify) <= 1 { break 'main; } diff --git a/src/download.rs b/src/download.rs index d76befc..8d8ca8a 100644 --- a/src/download.rs +++ b/src/download.rs @@ -78,7 +78,7 @@ pub struct Handle { } pub enum Output { - Loading(Progress), + Loading(Option), Queued(tracks::Queued), } @@ -88,7 +88,7 @@ impl Handle { Ok(queued) => Output::Queued(queued), Err(_) => { PROGRESS.store(0, atomic::Ordering::Relaxed); - Output::Loading(progress()) + Output::Loading(Some(progress())) } } } diff --git a/src/player.rs b/src/player.rs index 67f0e4b..47e35e5 100644 --- a/src/player.rs +++ b/src/player.rs @@ -17,10 +17,16 @@ use crate::{ #[derive(Clone, Debug)] pub enum Current { - Loading(download::Progress), + Loading(Option), Track(tracks::Info), } +impl Default for Current { + fn default() -> Self { + Current::Loading(None) + } +} + impl Current { pub fn loading(&self) -> bool { return matches!(self, Current::Loading(_)); @@ -35,15 +41,14 @@ pub struct Player { broadcast: broadcast::Sender, current: Current, ui: ui::Handle, + waiter: waiter::Handle, _tx: Sender, - _waiter: waiter::Handle, _stream: rodio::OutputStream, } impl Drop for Player { fn drop(&mut self) { self.sink.stop(); - self.broadcast.send(ui::Update::Quit).unwrap(); } } @@ -82,7 +87,7 @@ impl Player { let (tx, rx) = mpsc::channel(8); tx.send(Message::Init).await?; let (utx, urx) = broadcast::channel(8); - let current = Current::Loading(download::progress()); + let current = Current::Loading(None); let list = List::load(args.track_list.as_ref()).await?; let state = ui::State::initial(sink.clone(), &args, current.clone(), list.name.clone()); @@ -92,8 +97,8 @@ impl Player { Ok(Self { downloader: Downloader::init(args.buffer_size, list, tx.clone()).await, - ui: ui::Handle::init(tx.clone(), urx.resubscribe(), state.clone(), &args).await?, - _waiter: waiter::Handle::new(sink.clone(), tx.clone(), urx), + ui: ui::Handle::init(tx.clone(), urx, state, &args).await?, + waiter: waiter::Handle::new(sink.clone(), tx.clone()), bookmarks: Bookmarks::load().await?, current, broadcast: utx, @@ -115,6 +120,7 @@ impl Player { let decoded = queued.decode()?; self.sink.append(decoded.data); self.set_current(Current::Track(decoded.info)).await?; + self.waiter.notify(); Ok(()) } diff --git a/src/ui/components.rs b/src/ui/components.rs index 20a5d31..b93058e 100644 --- a/src/ui/components.rs +++ b/src/ui/components.rs @@ -66,7 +66,7 @@ enum ActionBar { Playing(tracks::Info), /// When the app is loading. - Loading(u8), + Loading(Option), /// When the app is muted. Muted, @@ -80,9 +80,9 @@ impl ActionBar { Self::Playing(x) => ("playing", Some((x.display.clone(), x.width))), Self::Paused(x) => ("paused", Some((x.display.clone(), x.width))), Self::Loading(progress) => { - let progress = format!("{: <2.0}%", progress.min(&99)); + let progress = progress.map(|progress| (format!("{: <2.0}%", progress.min(99)), 3)); - ("loading", Some((progress, 3))) + ("loading", progress) } Self::Muted => { let msg = "+ to increase volume"; @@ -108,7 +108,7 @@ impl ActionBar { pub fn action(state: &ui::State, width: usize) -> String { let action = match state.current.clone() { Current::Loading(progress) => { - ActionBar::Loading(progress.load(std::sync::atomic::Ordering::Relaxed)) + ActionBar::Loading(progress.map(|x| x.load(std::sync::atomic::Ordering::Relaxed))) } Current::Track(info) => { if state.sink.volume() < 0.01 {