transform simple queue to a preserving, more complex kind
this is a pretty big but necessary change and might not be stable yet. some key points: - the queue is now responsible for playback controls and track management, as this was scattered between the queue and spotify objects. - because the queue is now retained, it should be easier to save it as a spotify playlist closes #12
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use cursive::direction::Orientation;
|
||||
use cursive::event::Key;
|
||||
use cursive::traits::Boxable;
|
||||
use cursive::traits::Identifiable;
|
||||
use cursive::views::*;
|
||||
@@ -41,23 +42,46 @@ impl PlaylistView {
|
||||
}
|
||||
|
||||
fn create_button(&self, playlist: &SimplifiedPlaylist) -> SplitButton {
|
||||
let spotify_ref = self.spotify.clone();
|
||||
let queue_ref = self.queue.clone();
|
||||
|
||||
let id = playlist.id.clone();
|
||||
let collab = match playlist.collaborative {
|
||||
true => "collaborative",
|
||||
false => "",
|
||||
};
|
||||
|
||||
let mut button = SplitButton::new(&playlist.name, collab);
|
||||
button.add_callback(' ', move |_s| {
|
||||
let tracks = spotify_ref.user_playlist_tracks(&id).unwrap().items;
|
||||
let mut locked_queue = queue_ref.lock().expect("Could not aquire lock");
|
||||
for playlist_track in tracks {
|
||||
locked_queue.enqueue(Track::new(&playlist_track.track));
|
||||
}
|
||||
});
|
||||
|
||||
// <enter> plays the selected playlist
|
||||
{
|
||||
let id = playlist.id.clone();
|
||||
let spotify_ref = self.spotify.clone();
|
||||
let queue_ref = self.queue.clone();
|
||||
button.add_callback(Key::Enter, move |_s| {
|
||||
let tracks = spotify_ref.user_playlist_tracks(&id).unwrap().items;
|
||||
let mut locked_queue = queue_ref.lock().expect("Could not aquire lock");
|
||||
|
||||
let mut first_played = false;
|
||||
for playlist_track in tracks {
|
||||
let index = locked_queue.append_next(&Track::new(&playlist_track.track));
|
||||
if !first_played {
|
||||
locked_queue.play(index);
|
||||
first_played = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// <space> queues the selected playlist
|
||||
{
|
||||
let id = playlist.id.clone();
|
||||
let spotify_ref = self.spotify.clone();
|
||||
let queue_ref = self.queue.clone();
|
||||
button.add_callback(' ', move |_s| {
|
||||
let tracks = spotify_ref.user_playlist_tracks(&id).unwrap().items;
|
||||
let mut locked_queue = queue_ref.lock().expect("Could not aquire lock");
|
||||
for playlist_track in tracks {
|
||||
locked_queue.append(&Track::new(&playlist_track.track));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
button
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ use cursive::Cursive;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use queue::{Queue, QueueChange};
|
||||
use spotify::Spotify;
|
||||
use queue::{Queue, QueueEvent};
|
||||
use track::Track;
|
||||
use ui::splitbutton::SplitButton;
|
||||
use ui::trackbutton::TrackButton;
|
||||
@@ -17,11 +16,10 @@ use ui::trackbutton::TrackButton;
|
||||
pub struct QueueView {
|
||||
pub view: Option<Panel<BoxView<BoxView<ScrollView<IdView<LinearLayout>>>>>>, // FIXME: wow
|
||||
queue: Arc<Mutex<Queue>>,
|
||||
spotify: Arc<Spotify>,
|
||||
}
|
||||
|
||||
impl QueueView {
|
||||
pub fn new(queue: Arc<Mutex<Queue>>, spotify: Arc<Spotify>) -> QueueView {
|
||||
pub fn new(queue: Arc<Mutex<Queue>>) -> QueueView {
|
||||
let queuelist = LinearLayout::new(Orientation::Vertical).with_id("queue_list");
|
||||
let scrollable = ScrollView::new(queuelist).full_width().full_height();
|
||||
let panel = Panel::new(scrollable).title("Queue");
|
||||
@@ -29,7 +27,6 @@ impl QueueView {
|
||||
QueueView {
|
||||
view: Some(panel),
|
||||
queue: queue,
|
||||
spotify: spotify,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,33 +38,28 @@ impl QueueView {
|
||||
}
|
||||
}
|
||||
|
||||
fn cb_play(cursive: &mut Cursive, queue: &mut Queue, spotify: &Spotify) {
|
||||
fn cb_play(cursive: &mut Cursive, queue: &mut Queue) {
|
||||
let view_ref: Option<ViewRef<LinearLayout>> = cursive.find_id("queue_list");
|
||||
if let Some(queuelist) = view_ref {
|
||||
let index = queuelist.get_focus_index();
|
||||
let track = queue.remove(index).expect("could not dequeue track");
|
||||
spotify.load(track);
|
||||
spotify.play();
|
||||
queue.play(index);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ev(&self, cursive: &mut Cursive, ev: QueueChange) {
|
||||
pub fn handle_ev(&self, cursive: &mut Cursive, ev: QueueEvent) {
|
||||
let view_ref: Option<ViewRef<LinearLayout>> = cursive.find_id("queue_list");
|
||||
if let Some(mut queuelist) = view_ref {
|
||||
match ev {
|
||||
QueueChange::Enqueue => {
|
||||
QueueEvent::Add(index) => {
|
||||
let queue = self.queue.lock().expect("could not lock queue");
|
||||
let track = queue.peek().expect("queue is empty");
|
||||
let track = queue.get(index);
|
||||
let button = self.create_button(&track);
|
||||
queuelist.insert_child(0, button);
|
||||
queuelist.insert_child(index, button);
|
||||
}
|
||||
QueueChange::Dequeue => {
|
||||
queuelist.remove_child(0);
|
||||
}
|
||||
QueueChange::Remove(index) => {
|
||||
QueueEvent::Remove(index) => {
|
||||
queuelist.remove_child(index);
|
||||
}
|
||||
QueueChange::Show => self.populate(&mut queuelist),
|
||||
QueueEvent::Show => self.populate(&mut queuelist),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,15 +77,13 @@ impl QueueView {
|
||||
});
|
||||
}
|
||||
|
||||
// <enter> dequeues the selected track
|
||||
// <enter> plays the selected track
|
||||
{
|
||||
let queue_ref = self.queue.clone();
|
||||
let spotify = self.spotify.clone();
|
||||
button.add_callback(Key::Enter, move |cursive| {
|
||||
Self::cb_play(
|
||||
cursive,
|
||||
&mut queue_ref.lock().expect("could not lock queue"),
|
||||
&spotify,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -107,7 +97,7 @@ impl QueueView {
|
||||
|
||||
let queue = self.queue.lock().expect("could not lock queue");
|
||||
for track in queue.iter() {
|
||||
let button = self.create_button(&track);
|
||||
let button = self.create_button(track);
|
||||
queuelist.add_child(button);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ use ui::trackbutton::TrackButton;
|
||||
|
||||
pub struct SearchView {
|
||||
pub view: Panel<LinearLayout>,
|
||||
queue: Arc<Mutex<Queue>>,
|
||||
}
|
||||
|
||||
impl SearchView {
|
||||
@@ -32,23 +31,28 @@ impl SearchView {
|
||||
if let Ok(tracks) = tracks {
|
||||
for search_track in tracks.tracks.items {
|
||||
let track = Track::new(&search_track);
|
||||
|
||||
let s = spotify.clone();
|
||||
let mut button = TrackButton::new(&track);
|
||||
|
||||
// <enter> plays the selected track
|
||||
let t = track.clone();
|
||||
button.add_callback(Key::Enter, move |_cursive| {
|
||||
s.load(t.clone());
|
||||
s.play();
|
||||
});
|
||||
{
|
||||
let queue = queue.clone();
|
||||
let track = track.clone();
|
||||
button.add_callback(Key::Enter, move |_cursive| {
|
||||
let mut queue = queue.lock().unwrap();
|
||||
let index = queue.append_next(&track);
|
||||
queue.play(index);
|
||||
});
|
||||
}
|
||||
|
||||
// <space> queues the selected track
|
||||
let queue = queue.clone();
|
||||
button.add_callback(' ', move |_cursive| {
|
||||
let mut queue = queue.lock().unwrap();
|
||||
queue.enqueue(track.clone());
|
||||
});
|
||||
{
|
||||
let queue = queue.clone();
|
||||
let track = track.clone();
|
||||
button.add_callback(' ', move |_cursive| {
|
||||
let mut queue = queue.lock().unwrap();
|
||||
queue.append(&track);
|
||||
});
|
||||
}
|
||||
|
||||
results.add_child("", button);
|
||||
}
|
||||
@@ -72,9 +76,6 @@ impl SearchView {
|
||||
.child(searchfield)
|
||||
.child(scrollable);
|
||||
let rootpanel = Panel::new(layout).title("Search");
|
||||
return SearchView {
|
||||
view: rootpanel,
|
||||
queue: queue,
|
||||
};
|
||||
return SearchView { view: rootpanel };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use cursive::align::HAlign;
|
||||
use cursive::theme::ColorStyle;
|
||||
@@ -7,15 +7,20 @@ use cursive::vec::Vec2;
|
||||
use cursive::Printer;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use spotify::{PlayerStatus, Spotify};
|
||||
use queue::Queue;
|
||||
use spotify::{PlayerEvent, Spotify};
|
||||
|
||||
pub struct StatusBar {
|
||||
queue: Arc<Mutex<Queue>>,
|
||||
spotify: Arc<Spotify>,
|
||||
}
|
||||
|
||||
impl StatusBar {
|
||||
pub fn new(spotify: Arc<Spotify>) -> StatusBar {
|
||||
StatusBar { spotify: spotify }
|
||||
pub fn new(queue: Arc<Mutex<Queue>>, spotify: Arc<Spotify>) -> StatusBar {
|
||||
StatusBar {
|
||||
queue: queue,
|
||||
spotify: spotify,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +45,9 @@ impl View for StatusBar {
|
||||
});
|
||||
|
||||
let state_icon = match self.spotify.get_current_status() {
|
||||
PlayerStatus::Playing => " ▶ ",
|
||||
PlayerStatus::Paused => " ▮▮ ",
|
||||
PlayerStatus::Stopped => " ◼ ",
|
||||
PlayerEvent::Playing => " ▶ ",
|
||||
PlayerEvent::Paused => " ▮▮ ",
|
||||
PlayerEvent::Stopped | PlayerEvent::FinishedTrack => " ◼ ",
|
||||
}
|
||||
.to_string();
|
||||
|
||||
@@ -50,7 +55,12 @@ impl View for StatusBar {
|
||||
printer.print((0, 1), &state_icon);
|
||||
});
|
||||
|
||||
if let Some(ref t) = self.spotify.get_current_track() {
|
||||
if let Some(ref t) = self
|
||||
.queue
|
||||
.lock()
|
||||
.expect("could not lock queue")
|
||||
.get_current()
|
||||
{
|
||||
let elapsed = self.spotify.get_current_progress();
|
||||
let formatted_elapsed = format!(
|
||||
"{:02}:{:02}",
|
||||
|
||||
Reference in New Issue
Block a user