Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layout Change: Queue View Widget #485

Open
wants to merge 58 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
2295cef
Add ability to add to queue
May 7, 2024
856a70a
add ability to take queued song to other playlists, TODO: make it so …
May 10, 2024
7f0bab4
Add to queue rework - Now queues are held
May 12, 2024
ecd8546
Fix if switching contexts e.g: playing a different song from a differ…
May 31, 2024
9a99249
Change added_items to user_added_items, Lint using clippy.
Jun 16, 2024
8f13fdd
Linting done with format
Jun 16, 2024
bc9791f
Var name to user_items
Jun 16, 2024
a00272b
Remove redundant comment
Jun 16, 2024
4f5296a
UI change starting
Jun 19, 2024
6f27d9b
Merge branch 'master' of https://github.com/SO9010/psst
Jun 19, 2024
456a319
Queue view added (INCOMPLETE)
Jun 30, 2024
2ffb38a
Clear up
Jun 30, 2024
1b0d7c5
Remove from quieue buttom
Jun 30, 2024
b6fb954
Clean up and consistency...
jacksongoode Jul 2, 2024
67a7536
Center queue
jacksongoode Jul 2, 2024
ecb5256
Merge remote-tracking branch 'upstream/master'
Jul 12, 2024
abbc357
Align dividers
Jul 12, 2024
b67267d
Add left and right dividers
Jul 12, 2024
98f1824
Dynamically resize left side bar
Jul 14, 2024
d56ffcc
Allow long titles to break
jacksongoode Jul 14, 2024
6a1bf9f
Fix constraint causing issues
Jul 18, 2024
81f23cd
Merge branch 'master' of https://github.com/SO9010/psst
Jul 18, 2024
a60f52b
Improved widget switching
Jul 20, 2024
81d6ba0
More function, but it needs improvment.
Jul 20, 2024
e58b263
Fix overlap, this also makes the change in size smoother
Jul 21, 2024
5f59715
Hide queue if there are no items.
Jul 21, 2024
faf93b7
Lint
Jul 21, 2024
1c1e7bd
aha oops wrong way round
Jul 21, 2024
e9100c5
Info alert added
Jul 21, 2024
e976452
Remove by index
Jul 24, 2024
708c14f
Improved skipping method
Jul 25, 2024
57bd9c5
Add option to settings
Jul 25, 2024
f383da8
Clear queue
Jul 25, 2024
b9977aa
Fix oopsie and introduce context menu
Jul 25, 2024
40d1b6d
Merge branch 'jpochyla:master' into master
SO9010 Jul 25, 2024
8c3b1ae
Merge branch 'jpochyla:master' into master
SO9010 Jul 29, 2024
ceb9caa
Context menu update
Jul 29, 2024
9a62df4
Lint
Jul 29, 2024
17e60ba
Linting
jacksongoode Jul 30, 2024
c091fa1
Merge branch 'jpochyla:master' into master
SO9010 Aug 7, 2024
13215a7
Remove first song, need to clear some bugs now with removing from queue.
Aug 7, 2024
b308119
Fix remove from queue
Aug 7, 2024
5137a34
Fix skip to place in queue
Aug 7, 2024
13d4567
Lint
Aug 7, 2024
6e0e748
Fix queue repeats
Aug 9, 2024
3f48cbf
Merge branch 'jpochyla:master' into master
SO9010 Aug 24, 2024
2c4acfe
Fix dodgy playing
Aug 24, 2024
6ab7708
Linty
Aug 24, 2024
b42c7c9
Fix mistake
Aug 24, 2024
6f2d9b5
start to fix problems
Aug 26, 2024
cddcee0
start making it play if theres nothing there
Aug 27, 2024
ba9cbdb
Play even when no playlist is playing
Aug 27, 2024
ed3702e
Improvement
Aug 28, 2024
4e35a6c
Merge branch 'jpochyla:master' into master
SO9010 Sep 3, 2024
c7128f1
Lint!
Sep 19, 2024
9c61420
Merge branch 'jpochyla:master' into master
SO9010 Sep 23, 2024
f69b626
Merge branch 'jpochyla:master' into master
SO9010 Sep 26, 2024
5bf8a69
neaten appstate
Sep 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions psst-core/src/player/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ impl Player {
PlayerCommand::Seek { position } => self.seek(position),
PlayerCommand::Configure { config } => self.configure(config),
PlayerCommand::SetQueueBehavior { behavior } => self.queue.set_behaviour(behavior),
PlayerCommand::SkipToPlaceInQueue { item } => self.queue.skip_to_place_in_queue(item),
PlayerCommand::ClearQueue => self.queue.clear_user_items(),
PlayerCommand::AddToQueue { item } => self.queue.add(item),
PlayerCommand::RemoveFromQueue { item } => self.queue.remove(item),
PlayerCommand::SetVolume { volume } => self.set_volume(volume),
}
}
Expand Down Expand Up @@ -423,9 +426,16 @@ pub enum PlayerCommand {
SetQueueBehavior {
behavior: QueueBehavior,
},
SkipToPlaceInQueue {
item: usize,
},
AddToQueue {
item: PlaybackItem,
},
RemoveFromQueue {
item: usize,
},
ClearQueue,
/// Change playback volume to a value in 0.0..=1.0 range.
SetVolume {
volume: f64,
Expand Down
57 changes: 56 additions & 1 deletion psst-core/src/player/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,106 @@ impl Default for QueueBehavior {

pub struct Queue {
items: Vec<PlaybackItem>,
added_items_in_main_queue: Vec<(usize, usize)>,
user_items: Vec<PlaybackItem>,
position: usize,
user_items_position: usize,
positions: Vec<usize>,
behavior: QueueBehavior,
playing_from_user_items: bool,
}

impl Queue {
pub fn new() -> Self {
Self {
items: Vec::new(),
added_items_in_main_queue: Vec::new(),
user_items: Vec::new(),
position: 0,
user_items_position: 0,
positions: Vec::new(),
behavior: QueueBehavior::default(),
playing_from_user_items: false,
}
}

pub fn clear(&mut self) {
self.items.clear();
self.positions.clear();
self.position = 0;
}

pub fn clear_user_items(&mut self) {
self.user_items.clear();
self.user_items_position = 0;
}

pub fn fill(&mut self, items: Vec<PlaybackItem>, position: usize) {
self.positions.clear();
self.added_items_in_main_queue.clear();
self.items = items;
self.position = position;
self.compute_positions();
}

pub fn skip_to_place_in_queue(&mut self, index: usize) {
if self.playing_from_user_items {
self.user_items = self.user_items.split_off(index + 1);
}
else {
self.user_items = self.user_items.split_off(index);
}
self.user_items_position = 0;
}

pub fn add(&mut self, item: PlaybackItem) {
self.user_items.push(item);
}

pub fn get_playing_from_user_items_bool(&mut self) -> bool{
self.playing_from_user_items
}

pub fn remove(&mut self, index: usize) {
if self.playing_from_user_items {
self.user_items.remove(index+1);
}
else {
self.user_items.remove(index);
}
if self.user_items_position < index && self.user_items_position > 0 {
self.user_items_position -= 1;
}
}

fn handle_added_queue(&mut self) {
if !self.added_items_in_main_queue.is_empty() {
let item_index = self.added_items_in_main_queue[0].0;
let position_index = self.added_items_in_main_queue[0].1;
self.items.remove(item_index - 1);
self.positions.remove(position_index);

self.added_items_in_main_queue.remove(0);
if self.position > 0 {
self.position -= 1;
}
}

if self.user_items.len() > self.user_items_position {
self.items.insert(
self.positions.len(),
self.user_items[self.user_items_position],
);

self.positions
.insert(self.position + 1, self.positions.len());
self.user_items_position += 1;

self.added_items_in_main_queue.push((self.positions.len(), self.position + 1));
self.playing_from_user_items = true;
}
else {
self.playing_from_user_items = false;
}
}

Expand Down
2 changes: 1 addition & 1 deletion psst-gui/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn add_windows_icon() {
res.compile().expect("Could not attach exe icon");

fn load_images() -> Vec<IcoFrame<'static>> {
let sizes = vec![32, 64, 128, 256];
let sizes = [32, 64, 128, 256];
sizes
.iter()
.map(|s| {
Expand Down
5 changes: 5 additions & 0 deletions psst-gui/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ pub const ADD_TO_QUEUE: Selector<(QueueEntry, PlaybackItem)> = Selector::new("ap
pub const PLAY_QUEUE_BEHAVIOR: Selector<QueueBehavior> = Selector::new("app.play-queue-behavior");
pub const PLAY_SEEK: Selector<f64> = Selector::new("app.play-seek");

// Queue control
pub const REMOVE_FROM_QUEUE: Selector<usize> = Selector::new("app.remove-from-queue");
pub const CLEAR_QUEUE: Selector = Selector::new("app.clear-queue");
pub const SKIP_TO_PLACE_IN_QUEUE: Selector<usize> = Selector::new("app.skip-to-place-in-queue");

// Sorting control
pub const SORT_BY_DATE_ADDED: Selector = Selector::new("app.sort-by-date-added");
pub const SORT_BY_TITLE: Selector = Selector::new("app.sort-by-title");
Expand Down
70 changes: 68 additions & 2 deletions psst-gui/src/controller/playback.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{
thread::{self, JoinHandle},
time::Duration,
cmp::Ordering, thread::{self, JoinHandle}, time::Duration
};

use crossbeam_channel::Sender;
Expand Down Expand Up @@ -299,6 +298,19 @@ impl PlaybackController {
item: *item,
}));
}
fn skip_to_place_in_queue(&mut self, item: &usize) {
self.send(PlayerEvent::Command(PlayerCommand::SkipToPlaceInQueue {
item: *item,
}));
}
fn remove_from_queue(&mut self, item: &usize) {
self.send(PlayerEvent::Command(PlayerCommand::RemoveFromQueue {
item: *item,
}));
}
fn clear_queue(&mut self) {
self.send(PlayerEvent::Command(PlayerCommand::ClearQueue));
}

fn set_queue_behavior(&mut self, behavior: QueueBehavior) {
self.send(PlayerEvent::Command(PlayerCommand::SetQueueBehavior {
Expand Down Expand Up @@ -344,6 +356,13 @@ where
Event::Command(cmd) if cmd.is(cmd::PLAYBACK_PLAYING) => {
let (item, progress) = cmd.get_unchecked(cmd::PLAYBACK_PLAYING);

// TODO: this falsely removes the song if you click on a song from the playlist that is also in the queue, not sure how to solve this?
if !data.added_queue.displayed_queue.is_empty() && data.playback.now_playing.as_mut().is_some_and(|np| {
np.origin.to_string() == PlaybackOrigin::Queue.to_string()
&& np.item.id() == data.added_queue.displayed_queue[0].item.id()
}) {
data.added_queue.displayed_queue.remove(0);
}
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);
Expand Down Expand Up @@ -418,6 +437,7 @@ where

self.add_to_queue(item);
data.add_queued_entry(entry.clone());
data.info_alert("Track added to queue.");
ctx.set_handled();
}
Event::Command(cmd) if cmd.is(cmd::PLAY_QUEUE_BEHAVIOR) => {
Expand All @@ -436,6 +456,52 @@ where
}
ctx.set_handled();
}
Event::Command(cmd) if cmd.is(cmd::SKIP_TO_PLACE_IN_QUEUE) => {
let track_pos = *cmd.get_unchecked(cmd::SKIP_TO_PLACE_IN_QUEUE);
match track_pos.cmp(&0) {
Ordering::Greater => {
if data.playback.queue.is_empty() || (data.playback.queue.len() <= 1 && data.playback.queue[0].origin.to_string() == PlaybackOrigin::Queue.to_string()) {
data.playback.queue.clear();
data.playback.queue.push_back(data.added_queue.displayed_queue[track_pos].clone());
data.added_queue.displayed_queue = data.added_queue.displayed_queue.split_off(track_pos);
self.skip_to_place_in_queue(&(track_pos+1));
self.play(&data.playback.queue, track_pos);}
else if data.playback.now_playing.is_some() {
data.added_queue.displayed_queue = data.added_queue.displayed_queue.split_off(track_pos);
self.skip_to_place_in_queue(&track_pos);
self.next();
}
},
Ordering::Equal => {
if data.playback.queue.is_empty() || (data.playback.queue.len() <= 1 && data.playback.queue[0].origin.to_string() == PlaybackOrigin::Queue.to_string()) {
data.playback.queue.clear();
data.playback.queue.push_back(data.added_queue.displayed_queue[track_pos].clone());
self.remove_from_queue(&track_pos);
data.added_queue.displayed_queue.remove(track_pos);
self.play(&data.playback.queue, track_pos);
}
else if data.playback.now_playing.is_some() {
self.next();
}
}
_ => {}}

ctx.set_handled();
}
Event::Command(cmd) if cmd.is(cmd::REMOVE_FROM_QUEUE) => {
let item = cmd.get_unchecked(cmd::REMOVE_FROM_QUEUE);
data.added_queue.displayed_queue.remove(*item);
self.remove_from_queue(item);
data.info_alert("Track removed from queue.");

ctx.set_handled();
}
Event::Command(cmd) if cmd.is(cmd::CLEAR_QUEUE) => {
data.added_queue.displayed_queue.clear();
self.clear_queue();
data.info_alert("Tracks cleared from queue.");
ctx.set_handled();
}
// Keyboard shortcuts.
Event::KeyDown(key) if key.code == Code::Space => {
self.pause_or_resume();
Expand Down
2 changes: 2 additions & 0 deletions psst-gui/src/data/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub struct Config {
pub last_route: Option<Nav>,
pub queue_behavior: QueueBehavior,
pub show_track_cover: bool,
pub show_queue_view: bool,
pub window_size: Size,
pub slider_scroll_scale: SliderScrollScale,
pub sort_order: SortOrder,
Expand All @@ -112,6 +113,7 @@ impl Default for Config {
last_route: Default::default(),
queue_behavior: Default::default(),
show_track_cover: Default::default(),
show_queue_view: Default::default(),
window_size: Size::new(theme::grid(80.0), theme::grid(100.0)),
slider_scroll_scale: Default::default(),
sort_order: Default::default(),
Expand Down
22 changes: 17 additions & 5 deletions psst-gui/src/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,14 @@ pub struct AppState {
pub home_detail: HomeDetail,
pub alerts: Vector<Alert>,
pub finder: Finder,
pub added_queue: Vector<QueueEntry>,
pub added_queue: QueueFields,
}

#[derive(Clone, Data, Lens)]
pub struct QueueFields {
pub queue: Vector<QueueEntry>,
// TODO: This is a problem, due to added_queue never changing, the origin of a song, if also once added to the queue, will always be the queue.
pub displayed_queue: Vector<QueueEntry>,
}

impl AppState {
Expand Down Expand Up @@ -122,7 +129,10 @@ impl AppState {
cache_size: Promise::Empty,
},
playback,
added_queue: Vector::new(),
added_queue: QueueFields {
queue: Vector::new(),
displayed_queue: Vector::new(),
},
search: Search {
input: "".into(),
results: Promise::Empty,
Expand Down Expand Up @@ -193,15 +203,16 @@ impl AppState {
impl AppState {
pub fn queued_entry(&self, item_id: ItemId) -> Option<QueueEntry> {
if let Some(queued) = self
.playback
.added_queue
.queue
.iter()
.find(|queued| queued.item.id() == item_id)
.cloned()
{
Some(queued)
} else if let Some(queued) = self
.added_queue
.playback
.queue
.iter()
.find(|queued| queued.item.id() == item_id)
.cloned()
Expand All @@ -213,7 +224,8 @@ impl AppState {
}

pub fn add_queued_entry(&mut self, queue_entry: QueueEntry) {
self.added_queue.push_back(queue_entry);
self.added_queue.queue.push_back(queue_entry.clone());
self.added_queue.displayed_queue.push_back(queue_entry);
}

pub fn loading_playback(&mut self, item: Playable, origin: PlaybackOrigin) {
Expand Down
11 changes: 11 additions & 0 deletions psst-gui/src/data/playback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ impl Playable {
}
}

pub fn artist(&self) -> Arc<String> {
match self {
Playable::Track(track) => Arc::new(track.artist_names()),
Playable::Episode(episode) => Arc::new(episode.show.name.to_string()),
}
}

pub fn duration(&self) -> Duration {
match self {
Playable::Track(track) => track.duration,
Expand Down Expand Up @@ -109,6 +116,7 @@ impl NowPlaying {
pub enum PlaybackOrigin {
Home,
Library,
Queue,
Album(AlbumLink),
Artist(ArtistLink),
Playlist(PlaylistLink),
Expand All @@ -122,6 +130,8 @@ impl PlaybackOrigin {
match &self {
PlaybackOrigin::Home => Nav::Home,
PlaybackOrigin::Library => Nav::SavedTracks,
// Change this
PlaybackOrigin::Queue => Nav::Home,
PlaybackOrigin::Album(link) => Nav::AlbumDetail(link.clone()),
PlaybackOrigin::Artist(link) => Nav::ArtistDetail(link.clone()),
PlaybackOrigin::Playlist(link) => Nav::PlaylistDetail(link.clone()),
Expand All @@ -137,6 +147,7 @@ impl fmt::Display for PlaybackOrigin {
match &self {
PlaybackOrigin::Home => f.write_str("Home"),
PlaybackOrigin::Library => f.write_str("Saved Tracks"),
PlaybackOrigin::Queue => f.write_str("Queue"),
PlaybackOrigin::Album(link) => link.name.fmt(f),
PlaybackOrigin::Artist(link) => link.name.fmt(f),
PlaybackOrigin::Playlist(link) => link.name.fmt(f),
Expand Down
Loading