From 2295cef770190c38eb1840890924346bfc878f3a Mon Sep 17 00:00:00 2001 From: SO9010 Date: Tue, 7 May 2024 20:00:47 +0100 Subject: [PATCH 01/48] Add ability to add to queue --- README.md | 2 +- psst-core/src/player/mod.rs | 6 +++++- psst-core/src/player/queue.rs | 15 +++++++++++++++ psst-gui/src/cmd.rs | 3 ++- psst-gui/src/controller/playback.rs | 14 +++++++++++++- psst-gui/src/ui/track.rs | 12 ++++++++++++ 6 files changed, 48 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c4480393..8560cabc 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ cargo bundle --release - Reorder tracks - Rename playlist - Playlist folders -- [ ] Playback queue +- [x] Playback queue - [ ] React to audio output device events - Pause after disconnecting headphones - Transfer playback after connecting headphones diff --git a/psst-core/src/player/mod.rs b/psst-core/src/player/mod.rs index f05ba4ac..16c2a36b 100644 --- a/psst-core/src/player/mod.rs +++ b/psst-core/src/player/mod.rs @@ -119,6 +119,7 @@ impl Player { PlayerCommand::Seek { position } => self.seek(position), PlayerCommand::Configure { config } => self.configure(config), PlayerCommand::SetQueueBehavior { behavior } => self.queue.set_behaviour(behavior), + PlayerCommand::AddToQueue { item } => self.queue.add(item), PlayerCommand::SetVolume { volume } => self.set_volume(volume), } } @@ -282,7 +283,7 @@ impl Player { loading_handle, }; } - + fn set_volume(&mut self, volume: f64) { self.audio_output_sink.set_volume(volume as f32); } @@ -422,6 +423,9 @@ pub enum PlayerCommand { SetQueueBehavior { behavior: QueueBehavior, }, + AddToQueue{ + item: PlaybackItem, + }, /// Change playback volume to a value in 0.0..=1.0 range. SetVolume { volume: f64, diff --git a/psst-core/src/player/queue.rs b/psst-core/src/player/queue.rs index 771259b3..a40bb7d7 100644 --- a/psst-core/src/player/queue.rs +++ b/psst-core/src/player/queue.rs @@ -46,6 +46,21 @@ impl Queue { self.compute_positions(); } + pub fn add(&mut self, item: PlaybackItem) { + match self.behavior { + QueueBehavior::Random => { + self.compute_positions(); + self.items.insert(0, item); + self.positions.insert(self.position + 1, 0); + } + _ => { + // For other modes, insert the item at the current position + 1 + self.items.insert(self.position + 1, item); + } + } + } + + pub fn set_behaviour(&mut self, behavior: QueueBehavior) { self.behavior = behavior; self.compute_positions(); diff --git a/psst-gui/src/cmd.rs b/psst-gui/src/cmd.rs index 2073cbca..a9fdf518 100644 --- a/psst-gui/src/cmd.rs +++ b/psst-gui/src/cmd.rs @@ -1,7 +1,7 @@ use std::time::Duration; use druid::{Selector, WidgetId}; -use psst_core::item_id::ItemId; +use psst_core::{item_id::ItemId, player::item::PlaybackItem}; use crate::{ data::{Nav, PlaybackPayload, QueueBehavior}, @@ -56,6 +56,7 @@ pub const PLAY_PAUSE: Selector = Selector::new("app.play-pause"); pub const PLAY_RESUME: Selector = Selector::new("app.play-resume"); pub const PLAY_NEXT: Selector = Selector::new("app.play-next"); pub const PLAY_STOP: Selector = Selector::new("app.play-stop"); +pub const ADD_TO_QUEUE: Selector = Selector::new("app.add-to-queue"); pub const PLAY_QUEUE_BEHAVIOR: Selector = Selector::new("app.play-queue-behavior"); pub const PLAY_SEEK: Selector = Selector::new("app.play-seek"); diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index cd1db0ae..30f4033c 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -294,6 +294,12 @@ impl PlaybackController { self.send(PlayerEvent::Command(PlayerCommand::SetVolume { volume })); } + fn add_to_queue(&mut self, item: &PlaybackItem) { + self.send(PlayerEvent::Command(PlayerCommand::AddToQueue { + item: item.clone(), + })); + } + fn set_queue_behavior(&mut self, behavior: QueueBehavior) { self.send(PlayerEvent::Command(PlayerCommand::SetQueueBehavior { behavior: match behavior { @@ -310,7 +316,7 @@ impl Controller for PlaybackController where W: Widget, { - fn event( +fn event( &mut self, child: &mut W, ctx: &mut EventCtx, @@ -406,6 +412,12 @@ where self.stop(); ctx.set_handled(); } + Event::Command(cmd) if cmd.is(cmd::ADD_TO_QUEUE) => { + log::info!("adding to queue"); + let item = cmd.get_unchecked(cmd::ADD_TO_QUEUE); + self.add_to_queue(&item.to_owned()); + ctx.set_handled(); + } Event::Command(cmd) if cmd.is(cmd::PLAY_QUEUE_BEHAVIOR) => { let behavior = cmd.get_unchecked(cmd::PLAY_QUEUE_BEHAVIOR); data.set_queue_behavior(behavior.to_owned()); diff --git a/psst-gui/src/ui/track.rs b/psst-gui/src/ui/track.rs index 5f004d0e..b7b79a0c 100644 --- a/psst-gui/src/ui/track.rs +++ b/psst-gui/src/ui/track.rs @@ -4,6 +4,7 @@ use druid::{ widget::{CrossAxisAlignment, Either, Flex, Label, ViewSwitcher}, LensExt, LocalizedString, Menu, MenuItem, Size, TextAlignment, Widget, WidgetExt, }; +use psst_core::{audio::normalize::NormalizationLevel, item_id::{ItemId, ItemIdType}, player::item::PlaybackItem}; use crate::{ cmd, @@ -323,6 +324,17 @@ pub fn track_menu( } } + menu = menu.entry( + MenuItem::new( + LocalizedString::new("menu-item-add-to-queue").with_placeholder("Add Track To Queue"), + ) + //PlayerCommand + .command(cmd::ADD_TO_QUEUE.with(PlaybackItem{ + item_id: ItemId::from_base62(&String::from(track.id), ItemIdType::Track).unwrap(), + norm_level: NormalizationLevel::Track, + })), + ); + let mut playlist_menu = Menu::new( LocalizedString::new("menu-item-add-to-playlist").with_placeholder("Add to Playlist"), ); From 856a70aa47322bee9ee2017926ca5bd179a2824f Mon Sep 17 00:00:00 2001 From: SO9010 Date: Fri, 10 May 2024 14:09:32 +0100 Subject: [PATCH 02/48] add ability to take queued song to other playlists, TODO: make it so it passes the song so it can be displayed in the corner --- psst-core/src/player/queue.rs | 39 ++++++++++++++++++++--------- psst-gui/src/cmd.rs | 4 +-- psst-gui/src/controller/playback.rs | 14 +++++++++-- psst-gui/src/data/mod.rs | 9 +++++++ psst-gui/src/data/playback.rs | 1 + psst-gui/src/ui/track.rs | 7 +++--- 6 files changed, 54 insertions(+), 20 deletions(-) diff --git a/psst-core/src/player/queue.rs b/psst-core/src/player/queue.rs index a40bb7d7..9c9fa47e 100644 --- a/psst-core/src/player/queue.rs +++ b/psst-core/src/player/queue.rs @@ -18,7 +18,9 @@ impl Default for QueueBehavior { pub struct Queue { items: Vec, + added_items: Vec, position: usize, + added_items_position: usize, positions: Vec, behavior: QueueBehavior, } @@ -27,7 +29,9 @@ impl Queue { pub fn new() -> Self { Self { items: Vec::new(), + added_items: Vec::new(), position: 0, + added_items_position: 0, positions: Vec::new(), behavior: QueueBehavior::default(), } @@ -47,19 +51,22 @@ impl Queue { } pub fn add(&mut self, item: PlaybackItem) { - match self.behavior { - QueueBehavior::Random => { - self.compute_positions(); - self.items.insert(0, item); - self.positions.insert(self.position + 1, 0); - } - _ => { - // For other modes, insert the item at the current position + 1 - self.items.insert(self.position + 1, item); + self.added_items.push(item); + } + + fn handle_added_queue(&mut self){ + if self.added_items.len() > self.added_items_position { + self.compute_positions(); + self.items.insert(0, self.added_items[self.added_items_position]); + self.positions.insert(self.position + 1, 0); + self.added_items_position += 1; + + // Remove the past song from the queue as otherwise the queue will just go on for ever. + if self.added_items_position > 2 { + self.added_items.remove(0); } } } - pub fn set_behaviour(&mut self, behavior: QueueBehavior) { self.behavior = behavior; @@ -96,10 +103,12 @@ impl Queue { } pub fn skip_to_next(&mut self) { + self.handle_added_queue(); self.position = self.next_position(); } pub fn skip_to_following(&mut self) { + self.handle_added_queue(); self.position = self.following_position(); } @@ -109,8 +118,14 @@ impl Queue { } pub fn get_following(&self) -> Option<&PlaybackItem> { - let position = self.positions.get(self.following_position()).copied()?; - self.items.get(position) + if let Some(position) = self.positions.get(self.position).copied() { + if let Some(item) = self.items.get(position) { + return Some(item); + } + } else { + return self.added_items.get(0); + } + None } fn previous_position(&self) -> usize { diff --git a/psst-gui/src/cmd.rs b/psst-gui/src/cmd.rs index a9fdf518..7da915f4 100644 --- a/psst-gui/src/cmd.rs +++ b/psst-gui/src/cmd.rs @@ -4,7 +4,7 @@ use druid::{Selector, WidgetId}; use psst_core::{item_id::ItemId, player::item::PlaybackItem}; use crate::{ - data::{Nav, PlaybackPayload, QueueBehavior}, + data::{Nav, PlaybackPayload, PlaylistTracks, QueueBehavior, QueueEntry}, ui::find::Find, }; @@ -56,7 +56,7 @@ pub const PLAY_PAUSE: Selector = Selector::new("app.play-pause"); pub const PLAY_RESUME: Selector = Selector::new("app.play-resume"); pub const PLAY_NEXT: Selector = Selector::new("app.play-next"); pub const PLAY_STOP: Selector = Selector::new("app.play-stop"); -pub const ADD_TO_QUEUE: Selector = Selector::new("app.add-to-queue"); +pub const ADD_TO_QUEUE: Selector<(QueueEntry, PlaybackItem)> = Selector::new("app.add-to-queue"); pub const PLAY_QUEUE_BEHAVIOR: Selector = Selector::new("app.play-queue-behavior"); pub const PLAY_SEEK: Selector = Selector::new("app.play-seek"); diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index 30f4033c..e77ede69 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -348,7 +348,13 @@ fn event( data.start_playback(queued.item, queued.origin, progress.to_owned()); self.update_media_control_playback(&data.playback); self.update_media_control_metadata(&data.playback); - } else { + } else if let Some(queued) = data.queued_entry(*item) { + data.start_playback(queued.item, queued.origin, progress.to_owned()); + self.update_media_control_playback(&data.playback); + self.update_media_control_metadata(&data.playback); + } + + else { log::warn!("played item not found in playback queue"); } ctx.set_handled(); @@ -414,8 +420,12 @@ fn event( } Event::Command(cmd) if cmd.is(cmd::ADD_TO_QUEUE) => { log::info!("adding to queue"); - let item = cmd.get_unchecked(cmd::ADD_TO_QUEUE); + let (entry, item) = cmd.get_unchecked(cmd::ADD_TO_QUEUE); self.add_to_queue(&item.to_owned()); + data.playback.added_queue.push_back(QueueEntry { + item: entry.item.to_owned(), + origin: entry.origin.to_owned(), + }); ctx.set_handled(); } Event::Command(cmd) if cmd.is(cmd::PLAY_QUEUE_BEHAVIOR) => { diff --git a/psst-gui/src/data/mod.rs b/psst-gui/src/data/mod.rs index a2b93818..6c8461c4 100644 --- a/psst-gui/src/data/mod.rs +++ b/psst-gui/src/data/mod.rs @@ -101,6 +101,7 @@ impl AppState { now_playing: None, queue_behavior: config.queue_behavior, queue: Vector::new(), + added_queue: Vector::new(), volume: config.volume, }; Self { @@ -187,6 +188,14 @@ impl AppState { .cloned() } + pub fn added_queued_entry(&self, item_id: ItemId) -> Option { + self.playback + .queue + .iter() + .find(|queued| queued.item.id() == item_id) + .cloned() + } + pub fn loading_playback(&mut self, item: Playable, origin: PlaybackOrigin) { self.common_ctx_mut().now_playing.take(); self.playback.state = PlaybackState::Loading; diff --git a/psst-gui/src/data/playback.rs b/psst-gui/src/data/playback.rs index 7a99de1f..d6092306 100644 --- a/psst-gui/src/data/playback.rs +++ b/psst-gui/src/data/playback.rs @@ -16,6 +16,7 @@ pub struct Playback { pub now_playing: Option, pub queue_behavior: QueueBehavior, pub queue: Vector, + pub added_queue: Vector, pub volume: f64, } diff --git a/psst-gui/src/ui/track.rs b/psst-gui/src/ui/track.rs index b7b79a0c..a2702263 100644 --- a/psst-gui/src/ui/track.rs +++ b/psst-gui/src/ui/track.rs @@ -9,8 +9,7 @@ use psst_core::{audio::normalize::NormalizationLevel, item_id::{ItemId, ItemIdTy use crate::{ cmd, data::{ - AppState, Library, Nav, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack, - RecommendationsRequest, Track, + self, AppState, Library, Nav, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack, QueueEntry, RecommendationsRequest, Track }, ui::playlist, widget::{icons, Empty, MyWidgetExt, RemoteImage}, @@ -329,10 +328,10 @@ pub fn track_menu( LocalizedString::new("menu-item-add-to-queue").with_placeholder("Add Track To Queue"), ) //PlayerCommand - .command(cmd::ADD_TO_QUEUE.with(PlaybackItem{ + .command(cmd::ADD_TO_QUEUE.with((QueueEntry {item: crate::ui::Playable::Track(track.clone()), origin: origin.clone()}, PlaybackItem{ item_id: ItemId::from_base62(&String::from(track.id), ItemIdType::Track).unwrap(), norm_level: NormalizationLevel::Track, - })), + }))), ); let mut playlist_menu = Menu::new( From 7f0bab48f0a082aa3f1407b856cbc76011beba85 Mon Sep 17 00:00:00 2001 From: SO9010 Date: Sun, 12 May 2024 22:50:32 +0100 Subject: [PATCH 03/48] Add to queue rework - Now queues are held --- psst-gui/src/cmd.rs | 2 +- psst-gui/src/controller/playback.rs | 11 ++--------- psst-gui/src/data/mod.rs | 26 +++++++++++++------------- psst-gui/src/ui/track.rs | 2 +- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/psst-gui/src/cmd.rs b/psst-gui/src/cmd.rs index 7da915f4..49a7670a 100644 --- a/psst-gui/src/cmd.rs +++ b/psst-gui/src/cmd.rs @@ -4,7 +4,7 @@ use druid::{Selector, WidgetId}; use psst_core::{item_id::ItemId, player::item::PlaybackItem}; use crate::{ - data::{Nav, PlaybackPayload, PlaylistTracks, QueueBehavior, QueueEntry}, + data::{Nav, PlaybackPayload, QueueBehavior, QueueEntry}, ui::find::Find, }; diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index e77ede69..0a01f23c 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -348,12 +348,7 @@ fn event( data.start_playback(queued.item, queued.origin, progress.to_owned()); self.update_media_control_playback(&data.playback); self.update_media_control_metadata(&data.playback); - } else if let Some(queued) = data.queued_entry(*item) { - data.start_playback(queued.item, queued.origin, progress.to_owned()); - self.update_media_control_playback(&data.playback); - self.update_media_control_metadata(&data.playback); } - else { log::warn!("played item not found in playback queue"); } @@ -421,11 +416,9 @@ fn event( Event::Command(cmd) if cmd.is(cmd::ADD_TO_QUEUE) => { log::info!("adding to queue"); let (entry, item) = cmd.get_unchecked(cmd::ADD_TO_QUEUE); + self.add_to_queue(&item.to_owned()); - data.playback.added_queue.push_back(QueueEntry { - item: entry.item.to_owned(), - origin: entry.origin.to_owned(), - }); + data.add_queued_entry(entry.clone()); ctx.set_handled(); } Event::Command(cmd) if cmd.is(cmd::PLAY_QUEUE_BEHAVIOR) => { diff --git a/psst-gui/src/data/mod.rs b/psst-gui/src/data/mod.rs index 6c8461c4..a094c318 100644 --- a/psst-gui/src/data/mod.rs +++ b/psst-gui/src/data/mod.rs @@ -181,19 +181,19 @@ impl AppState { impl AppState { pub fn queued_entry(&self, item_id: ItemId) -> Option { - self.playback - .queue - .iter() - .find(|queued| queued.item.id() == item_id) - .cloned() - } - - pub fn added_queued_entry(&self, item_id: ItemId) -> Option { - self.playback - .queue - .iter() - .find(|queued| queued.item.id() == item_id) - .cloned() + if let Some(queued) = self.playback.queue.iter().find(|queued| queued.item.id() == item_id).cloned() { + return Some(queued); + } else if let Some(queued) = self.playback.added_queue.iter().find(|queued| queued.item.id() == item_id).cloned() { + return Some(queued); + } else { + None + } + } + + pub fn add_queued_entry(&mut self, queue_entry: QueueEntry) { + // it still gets updated and wiped when playlsit changes + self.playback.added_queue.push_back(queue_entry); + } pub fn loading_playback(&mut self, item: Playable, origin: PlaybackOrigin) { diff --git a/psst-gui/src/ui/track.rs b/psst-gui/src/ui/track.rs index a2702263..a1106b31 100644 --- a/psst-gui/src/ui/track.rs +++ b/psst-gui/src/ui/track.rs @@ -9,7 +9,7 @@ use psst_core::{audio::normalize::NormalizationLevel, item_id::{ItemId, ItemIdTy use crate::{ cmd, data::{ - self, AppState, Library, Nav, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack, QueueEntry, RecommendationsRequest, Track + AppState, Library, Nav, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack, QueueEntry, RecommendationsRequest, Track }, ui::playlist, widget::{icons, Empty, MyWidgetExt, RemoteImage}, From ecd8546bf39d0768963109c9a6868744051353b9 Mon Sep 17 00:00:00 2001 From: SO9010 Date: Fri, 31 May 2024 11:30:50 +0100 Subject: [PATCH 04/48] Fix if switching contexts e.g: playing a different song from a different album, retains added queue. --- psst-core/src/player/queue.rs | 9 ++++----- psst-gui/src/data/mod.rs | 7 ++++--- psst-gui/src/data/playback.rs | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/psst-core/src/player/queue.rs b/psst-core/src/player/queue.rs index 9c9fa47e..244f8288 100644 --- a/psst-core/src/player/queue.rs +++ b/psst-core/src/player/queue.rs @@ -56,15 +56,14 @@ impl Queue { fn handle_added_queue(&mut self){ if self.added_items.len() > self.added_items_position { - self.compute_positions(); - self.items.insert(0, self.added_items[self.added_items_position]); - self.positions.insert(self.position + 1, 0); + self.items.insert(self.positions.len(), self.added_items[self.added_items_position]); + self.positions.insert(self.position + 1, self.positions.len()); self.added_items_position += 1; - // Remove the past song from the queue as otherwise the queue will just go on for ever. if self.added_items_position > 2 { self.added_items.remove(0); - } + self.added_items_position -= 1; + } } } diff --git a/psst-gui/src/data/mod.rs b/psst-gui/src/data/mod.rs index a094c318..cbf9c770 100644 --- a/psst-gui/src/data/mod.rs +++ b/psst-gui/src/data/mod.rs @@ -80,6 +80,7 @@ pub struct AppState { pub personalized: Personalized, pub alerts: Vector, pub finder: Finder, + pub added_queue: Vector, } impl AppState { @@ -101,7 +102,6 @@ impl AppState { now_playing: None, queue_behavior: config.queue_behavior, queue: Vector::new(), - added_queue: Vector::new(), volume: config.volume, }; Self { @@ -119,6 +119,7 @@ impl AppState { cache_size: Promise::Empty, }, playback, + added_queue: Vector::new(), search: Search { input: "".into(), results: Promise::Empty, @@ -183,7 +184,7 @@ impl AppState { pub fn queued_entry(&self, item_id: ItemId) -> Option { if let Some(queued) = self.playback.queue.iter().find(|queued| queued.item.id() == item_id).cloned() { return Some(queued); - } else if let Some(queued) = self.playback.added_queue.iter().find(|queued| queued.item.id() == item_id).cloned() { + } else if let Some(queued) = self.added_queue.iter().find(|queued| queued.item.id() == item_id).cloned() { return Some(queued); } else { None @@ -192,7 +193,7 @@ impl AppState { pub fn add_queued_entry(&mut self, queue_entry: QueueEntry) { // it still gets updated and wiped when playlsit changes - self.playback.added_queue.push_back(queue_entry); + self.added_queue.push_back(queue_entry); } diff --git a/psst-gui/src/data/playback.rs b/psst-gui/src/data/playback.rs index d6092306..7a99de1f 100644 --- a/psst-gui/src/data/playback.rs +++ b/psst-gui/src/data/playback.rs @@ -16,7 +16,6 @@ pub struct Playback { pub now_playing: Option, pub queue_behavior: QueueBehavior, pub queue: Vector, - pub added_queue: Vector, pub volume: f64, } From 9a9924963cc65e733e65a45c832050eeb326b84c Mon Sep 17 00:00:00 2001 From: SO9010 Date: Sun, 16 Jun 2024 16:51:06 +0100 Subject: [PATCH 05/48] Change added_items to user_added_items, Lint using clippy. --- psst-core/src/player/queue.rs | 23 +++++++++-------------- psst-gui/src/controller/playback.rs | 2 +- psst-gui/src/data/mod.rs | 2 +- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/psst-core/src/player/queue.rs b/psst-core/src/player/queue.rs index 244f8288..da1c730a 100644 --- a/psst-core/src/player/queue.rs +++ b/psst-core/src/player/queue.rs @@ -18,9 +18,9 @@ impl Default for QueueBehavior { pub struct Queue { items: Vec, - added_items: Vec, + user_added_items: Vec, position: usize, - added_items_position: usize, + user_added_items_position: usize, positions: Vec, behavior: QueueBehavior, } @@ -29,9 +29,9 @@ impl Queue { pub fn new() -> Self { Self { items: Vec::new(), - added_items: Vec::new(), + user_added_items: Vec::new(), position: 0, - added_items_position: 0, + user_added_items_position: 0, positions: Vec::new(), behavior: QueueBehavior::default(), } @@ -51,19 +51,14 @@ impl Queue { } pub fn add(&mut self, item: PlaybackItem) { - self.added_items.push(item); + self.user_added_items.push(item); } fn handle_added_queue(&mut self){ - if self.added_items.len() > self.added_items_position { - self.items.insert(self.positions.len(), self.added_items[self.added_items_position]); + if self.user_added_items.len() > self.user_added_items_position { + self.items.insert(self.positions.len(), self.user_added_items[self.user_added_items_position]); self.positions.insert(self.position + 1, self.positions.len()); - self.added_items_position += 1; - - if self.added_items_position > 2 { - self.added_items.remove(0); - self.added_items_position -= 1; - } + self.user_added_items_position += 1; } } @@ -122,7 +117,7 @@ impl Queue { return Some(item); } } else { - return self.added_items.get(0); + return self.user_added_items.first(); } None } diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index 0a01f23c..8e6c1daf 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -296,7 +296,7 @@ impl PlaybackController { fn add_to_queue(&mut self, item: &PlaybackItem) { self.send(PlayerEvent::Command(PlayerCommand::AddToQueue { - item: item.clone(), + item: *item, })); } diff --git a/psst-gui/src/data/mod.rs b/psst-gui/src/data/mod.rs index cbf9c770..5357b49a 100644 --- a/psst-gui/src/data/mod.rs +++ b/psst-gui/src/data/mod.rs @@ -183,7 +183,7 @@ impl AppState { impl AppState { pub fn queued_entry(&self, item_id: ItemId) -> Option { if let Some(queued) = self.playback.queue.iter().find(|queued| queued.item.id() == item_id).cloned() { - return Some(queued); + Some(queued) } else if let Some(queued) = self.added_queue.iter().find(|queued| queued.item.id() == item_id).cloned() { return Some(queued); } else { From 8f13fddd1aa7ed829ae662a283cc669c67396cca Mon Sep 17 00:00:00 2001 From: SO9010 Date: Sun, 16 Jun 2024 17:04:05 +0100 Subject: [PATCH 06/48] Linting done with format --- psst-core/src/player/mod.rs | 4 ++-- psst-core/src/player/queue.rs | 10 +++++++--- psst-gui/src/controller/playback.rs | 11 +++++------ psst-gui/src/data/mod.rs | 16 +++++++++++++--- psst-gui/src/ui/track.rs | 23 +++++++++++++++++------ 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/psst-core/src/player/mod.rs b/psst-core/src/player/mod.rs index 16c2a36b..735ba654 100644 --- a/psst-core/src/player/mod.rs +++ b/psst-core/src/player/mod.rs @@ -283,7 +283,7 @@ impl Player { loading_handle, }; } - + fn set_volume(&mut self, volume: f64) { self.audio_output_sink.set_volume(volume as f32); } @@ -423,7 +423,7 @@ pub enum PlayerCommand { SetQueueBehavior { behavior: QueueBehavior, }, - AddToQueue{ + AddToQueue { item: PlaybackItem, }, /// Change playback volume to a value in 0.0..=1.0 range. diff --git a/psst-core/src/player/queue.rs b/psst-core/src/player/queue.rs index da1c730a..66715924 100644 --- a/psst-core/src/player/queue.rs +++ b/psst-core/src/player/queue.rs @@ -54,10 +54,14 @@ impl Queue { self.user_added_items.push(item); } - fn handle_added_queue(&mut self){ + fn handle_added_queue(&mut self) { if self.user_added_items.len() > self.user_added_items_position { - self.items.insert(self.positions.len(), self.user_added_items[self.user_added_items_position]); - self.positions.insert(self.position + 1, self.positions.len()); + self.items.insert( + self.positions.len(), + self.user_added_items[self.user_added_items_position], + ); + self.positions + .insert(self.position + 1, self.positions.len()); self.user_added_items_position += 1; } } diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index 8e6c1daf..79b8b811 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -296,8 +296,8 @@ impl PlaybackController { fn add_to_queue(&mut self, item: &PlaybackItem) { self.send(PlayerEvent::Command(PlayerCommand::AddToQueue { - item: *item, - })); + item: *item, + })); } fn set_queue_behavior(&mut self, behavior: QueueBehavior) { @@ -316,7 +316,7 @@ impl Controller for PlaybackController where W: Widget, { -fn event( + fn event( &mut self, child: &mut W, ctx: &mut EventCtx, @@ -348,8 +348,7 @@ fn event( data.start_playback(queued.item, queued.origin, progress.to_owned()); self.update_media_control_playback(&data.playback); self.update_media_control_metadata(&data.playback); - } - else { + } else { log::warn!("played item not found in playback queue"); } ctx.set_handled(); @@ -417,7 +416,7 @@ fn event( log::info!("adding to queue"); let (entry, item) = cmd.get_unchecked(cmd::ADD_TO_QUEUE); - self.add_to_queue(&item.to_owned()); + self.add_to_queue(item); data.add_queued_entry(entry.clone()); ctx.set_handled(); } diff --git a/psst-gui/src/data/mod.rs b/psst-gui/src/data/mod.rs index 5357b49a..2ebd6cb7 100644 --- a/psst-gui/src/data/mod.rs +++ b/psst-gui/src/data/mod.rs @@ -182,9 +182,20 @@ impl AppState { impl AppState { pub fn queued_entry(&self, item_id: ItemId) -> Option { - if let Some(queued) = self.playback.queue.iter().find(|queued| queued.item.id() == item_id).cloned() { + if let Some(queued) = self + .playback + .queue + .iter() + .find(|queued| queued.item.id() == item_id) + .cloned() + { Some(queued) - } else if let Some(queued) = self.added_queue.iter().find(|queued| queued.item.id() == item_id).cloned() { + } else if let Some(queued) = self + .added_queue + .iter() + .find(|queued| queued.item.id() == item_id) + .cloned() + { return Some(queued); } else { None @@ -194,7 +205,6 @@ impl AppState { pub fn add_queued_entry(&mut self, queue_entry: QueueEntry) { // it still gets updated and wiped when playlsit changes self.added_queue.push_back(queue_entry); - } pub fn loading_playback(&mut self, item: Playable, origin: PlaybackOrigin) { diff --git a/psst-gui/src/ui/track.rs b/psst-gui/src/ui/track.rs index a1106b31..bcb25d03 100644 --- a/psst-gui/src/ui/track.rs +++ b/psst-gui/src/ui/track.rs @@ -4,12 +4,17 @@ use druid::{ widget::{CrossAxisAlignment, Either, Flex, Label, ViewSwitcher}, LensExt, LocalizedString, Menu, MenuItem, Size, TextAlignment, Widget, WidgetExt, }; -use psst_core::{audio::normalize::NormalizationLevel, item_id::{ItemId, ItemIdType}, player::item::PlaybackItem}; +use psst_core::{ + audio::normalize::NormalizationLevel, + item_id::{ItemId, ItemIdType}, + player::item::PlaybackItem, +}; use crate::{ cmd, data::{ - AppState, Library, Nav, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack, QueueEntry, RecommendationsRequest, Track + AppState, Library, Nav, PlaybackOrigin, PlaylistAddTrack, PlaylistRemoveTrack, QueueEntry, + RecommendationsRequest, Track, }, ui::playlist, widget::{icons, Empty, MyWidgetExt, RemoteImage}, @@ -328,10 +333,16 @@ pub fn track_menu( LocalizedString::new("menu-item-add-to-queue").with_placeholder("Add Track To Queue"), ) //PlayerCommand - .command(cmd::ADD_TO_QUEUE.with((QueueEntry {item: crate::ui::Playable::Track(track.clone()), origin: origin.clone()}, PlaybackItem{ - item_id: ItemId::from_base62(&String::from(track.id), ItemIdType::Track).unwrap(), - norm_level: NormalizationLevel::Track, - }))), + .command(cmd::ADD_TO_QUEUE.with(( + QueueEntry { + item: crate::ui::Playable::Track(track.clone()), + origin: origin.clone(), + }, + PlaybackItem { + item_id: ItemId::from_base62(&String::from(track.id), ItemIdType::Track).unwrap(), + norm_level: NormalizationLevel::Track, + }, + ))), ); let mut playlist_menu = Menu::new( From bc9791fcb40b3fa19561bbc7f5c07b4716b46d17 Mon Sep 17 00:00:00 2001 From: SO9010 Date: Sun, 16 Jun 2024 17:05:27 +0100 Subject: [PATCH 07/48] Var name to user_items --- psst-core/src/player/queue.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/psst-core/src/player/queue.rs b/psst-core/src/player/queue.rs index 66715924..acbea36e 100644 --- a/psst-core/src/player/queue.rs +++ b/psst-core/src/player/queue.rs @@ -18,9 +18,9 @@ impl Default for QueueBehavior { pub struct Queue { items: Vec, - user_added_items: Vec, + user_items: Vec, position: usize, - user_added_items_position: usize, + user_items_position: usize, positions: Vec, behavior: QueueBehavior, } @@ -29,9 +29,9 @@ impl Queue { pub fn new() -> Self { Self { items: Vec::new(), - user_added_items: Vec::new(), + user_items: Vec::new(), position: 0, - user_added_items_position: 0, + user_items_position: 0, positions: Vec::new(), behavior: QueueBehavior::default(), } @@ -51,18 +51,18 @@ impl Queue { } pub fn add(&mut self, item: PlaybackItem) { - self.user_added_items.push(item); + self.user_items.push(item); } fn handle_added_queue(&mut self) { - if self.user_added_items.len() > self.user_added_items_position { + if self.user_items.len() > self.user_items_position { self.items.insert( self.positions.len(), - self.user_added_items[self.user_added_items_position], + self.user_items[self.user_items_position], ); self.positions .insert(self.position + 1, self.positions.len()); - self.user_added_items_position += 1; + self.user_items_position += 1; } } @@ -121,7 +121,7 @@ impl Queue { return Some(item); } } else { - return self.user_added_items.first(); + return self.user_items.first(); } None } From a00272b31e7ae20ea55ae09b178b06b3bfd75239 Mon Sep 17 00:00:00 2001 From: SO9010 Date: Sun, 16 Jun 2024 20:34:18 +0100 Subject: [PATCH 08/48] Remove redundant comment --- psst-gui/src/data/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/psst-gui/src/data/mod.rs b/psst-gui/src/data/mod.rs index 2ebd6cb7..02ff7779 100644 --- a/psst-gui/src/data/mod.rs +++ b/psst-gui/src/data/mod.rs @@ -203,7 +203,6 @@ impl AppState { } pub fn add_queued_entry(&mut self, queue_entry: QueueEntry) { - // it still gets updated and wiped when playlsit changes self.added_queue.push_back(queue_entry); } From 4f5296a4f5d8e4125d6e9a049ed8fa33242715d4 Mon Sep 17 00:00:00 2001 From: SO9010 Date: Wed, 19 Jun 2024 16:35:19 +0100 Subject: [PATCH 09/48] UI change starting --- psst-core/src/player/queue.rs | 4 +++ psst-gui/src/controller/playback.rs | 2 +- psst-gui/src/ui/mod.rs | 49 +++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/psst-core/src/player/queue.rs b/psst-core/src/player/queue.rs index acbea36e..512fda8b 100644 --- a/psst-core/src/player/queue.rs +++ b/psst-core/src/player/queue.rs @@ -53,6 +53,10 @@ impl Queue { pub fn add(&mut self, item: PlaybackItem) { self.user_items.push(item); } + + pub fn get_user_queue(&mut self) -> &[PlaybackItem]{ + &self.user_items + } fn handle_added_queue(&mut self) { if self.user_items.len() > self.user_items_position { diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index 79b8b811..421edb81 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -13,7 +13,7 @@ use psst_core::{ audio::{normalize::NormalizationLevel, output::DefaultAudioOutput}, cache::Cache, cdn::Cdn, - player::{item::PlaybackItem, PlaybackConfig, Player, PlayerCommand, PlayerEvent}, + player::{item::PlaybackItem, queue, PlaybackConfig, Player, PlayerCommand, PlayerEvent}, session::SessionService, }; use souvlaki::{ diff --git a/psst-gui/src/ui/mod.rs b/psst-gui/src/ui/mod.rs index c9237e26..5fa78738 100644 --- a/psst-gui/src/ui/mod.rs +++ b/psst-gui/src/ui/mod.rs @@ -1,14 +1,12 @@ use std::time::Duration; use druid::{ - im::Vector, - lens::Unit, - widget::{CrossAxisAlignment, Either, Flex, Label, List, Scroll, Slider, Split, ViewSwitcher}, - Color, Env, Insets, Key, LensExt, Menu, MenuItem, Selector, Widget, WidgetExt, WindowDesc, + im::Vector, lens::Unit, theme::{BACKGROUND_DARK, BUTTON_DARK, PRIMARY_LIGHT}, widget::{CrossAxisAlignment, Either, Flex, Label, LabelText, LineBreaking, List, Padding, Scroll, Slider, Split, ViewSwitcher}, Color, Env, Insets, Key, LensExt, Menu, MenuItem, Selector, Widget, WidgetExt, WindowDesc }; use druid_shell::Cursor; +use psst_core::player::queue; -use crate::data::config::SortCriteria; +use crate::data::{app_state_derived_lenses::added_queue, config::SortCriteria, QueueEntry}; use crate::{ cmd, controller::{AfterDelay, NavController, SessionController, SortController}, @@ -152,13 +150,23 @@ fn root_widget() -> impl Widget { .with_flex_child(Overlay::bottom(route_widget(), alert_widget()), 1.0) .with_child(playback::panel_widget()) .background(theme::BACKGROUND_LIGHT); + + let queues = Flex::column() + .cross_axis_alignment(CrossAxisAlignment::Start) + .with_flex_child(queue_widget(), 1.0) + .background(theme::BACKGROUND_LIGHT); - let split = Split::columns(sidebar, main) - .split_point(0.2) + let split = Split::columns(sidebar, Split::columns(main, queues) + .split_point(0.85) .bar_size(1.0) - .min_size(150.0, 300.0) + .min_size(300.0, 150.0) .min_bar_area(1.0) - .solid_bar(true); + .solid_bar(true)) + .split_point(0.2) + .bar_size(1.0) + .min_size(150.0, 300.0) + .min_bar_area(1.0) + .solid_bar(true); ThemeScope::new(split) .controller(SessionController) @@ -169,6 +177,29 @@ fn root_widget() -> impl Widget { // .debug_paint_layout() } + + +fn queue_list_widget() -> impl Widget> { + List::new(|| { + Flex::row() + .with_child(Label::new(|item: &QueueEntry, _env: &Env| item.item.name().to_string()) + .with_line_break_mode(LineBreaking::Clip) + .with_font(theme::UI_FONT_MEDIUM) + .padding(theme::grid(1.0)) + .link() + .rounded(10.0) + ) + }) +} + +fn queue_widget() -> impl Widget { + Scroll::new(Padding::new(7.5, queue_list_widget())) + .vertical() + .lens(AppState::added_queue) + .background(BACKGROUND_DARK) + .rounded(10.0) +} + fn alert_widget() -> impl Widget { const BG: Key = Key::new("app.alert.BG"); const DISMISS_ALERT: Selector = Selector::new("app.alert.dismiss"); From 456a319e946be1b967ad376e7e6a47bbee0a527f Mon Sep 17 00:00:00 2001 From: SO9010 Date: Sun, 30 Jun 2024 13:01:18 +0100 Subject: [PATCH 10/48] Queue view added (INCOMPLETE) --- psst-gui/src/cmd.rs | 2 + psst-gui/src/controller/playback.rs | 10 ++- psst-gui/src/data/mod.rs | 2 + psst-gui/src/data/playback.rs | 7 ++ psst-gui/src/ui/mod.rs | 60 ++++------------- psst-gui/src/ui/queued.rs | 101 ++++++++++++++++++++++++++++ psst-gui/src/ui/recommend.rs | 1 + psst-gui/src/widget/utils.rs | 14 +++- 8 files changed, 149 insertions(+), 48 deletions(-) create mode 100644 psst-gui/src/ui/queued.rs diff --git a/psst-gui/src/cmd.rs b/psst-gui/src/cmd.rs index 49a7670a..17d2b21c 100644 --- a/psst-gui/src/cmd.rs +++ b/psst-gui/src/cmd.rs @@ -55,6 +55,8 @@ pub const PLAY_PREVIOUS: Selector = Selector::new("app.play-previous"); pub const PLAY_PAUSE: Selector = Selector::new("app.play-pause"); pub const PLAY_RESUME: Selector = Selector::new("app.play-resume"); pub const PLAY_NEXT: Selector = Selector::new("app.play-next"); +// Todo Skip by +pub const SKIP_BY: Selector = Selector::new("app.skip-by"); pub const PLAY_STOP: Selector = Selector::new("app.play-stop"); pub const ADD_TO_QUEUE: Selector<(QueueEntry, PlaybackItem)> = Selector::new("app.add-to-queue"); pub const PLAY_QUEUE_BEHAVIOR: Selector = Selector::new("app.play-queue-behavior"); diff --git a/psst-gui/src/controller/playback.rs b/psst-gui/src/controller/playback.rs index 421edb81..cd7cdfa7 100644 --- a/psst-gui/src/controller/playback.rs +++ b/psst-gui/src/controller/playback.rs @@ -13,7 +13,7 @@ use psst_core::{ audio::{normalize::NormalizationLevel, output::DefaultAudioOutput}, cache::Cache, cdn::Cdn, - player::{item::PlaybackItem, queue, PlaybackConfig, Player, PlayerCommand, PlayerEvent}, + player::{item::PlaybackItem, PlaybackConfig, Player, PlayerCommand, PlayerEvent}, session::SessionService, }; use souvlaki::{ @@ -265,6 +265,10 @@ impl PlaybackController { fn next(&mut self) { self.send(PlayerEvent::Command(PlayerCommand::Next)); } + // Implemet properly, this will only skip by one, we need to use the inc val + fn skip_by(&mut self, inc: i32) { + self.send(PlayerEvent::Command(PlayerCommand::Next)); + } fn stop(&mut self) { self.send(PlayerEvent::Command(PlayerCommand::Stop)); @@ -408,6 +412,10 @@ where self.next(); ctx.set_handled(); } + Event::Command(cmd) if cmd.is(cmd::SKIP_BY) => { + // self. + // ctx.set_handled(); + } Event::Command(cmd) if cmd.is(cmd::PLAY_STOP) => { self.stop(); ctx.set_handled(); diff --git a/psst-gui/src/data/mod.rs b/psst-gui/src/data/mod.rs index 02ff7779..d6cd0c59 100644 --- a/psst-gui/src/data/mod.rs +++ b/psst-gui/src/data/mod.rs @@ -65,6 +65,7 @@ pub struct AppState { #[data(ignore)] pub session: SessionService, pub nav: Nav, + pub show_queue: bool, pub history: Vector