more refined queue events + playlist delete binding
- move from listview to linearlayout + scrollview - doesn't redraw the whole view on queue changes anymore - uses new cursive functions for linearlayout (needs cursive git) closes #3
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use crossbeam_channel::{unbounded, Receiver, Sender, TryIter};
|
||||
use cursive::{CbFunc, Cursive};
|
||||
|
||||
use queue::QueueChange;
|
||||
use spotify::PlayerState;
|
||||
|
||||
pub enum Event {
|
||||
QueueUpdate,
|
||||
Queue(QueueChange),
|
||||
Player(PlayerState),
|
||||
}
|
||||
|
||||
|
||||
12
src/main.rs
12
src/main.rs
@@ -37,6 +37,7 @@ mod theme;
|
||||
mod ui;
|
||||
|
||||
use events::{Event, EventManager};
|
||||
use queue::QueueChange;
|
||||
|
||||
fn init_logger(content: TextContent) {
|
||||
let mut builder = env_logger::Builder::from_default_env();
|
||||
@@ -100,6 +101,7 @@ fn main() {
|
||||
|
||||
cursive.add_global_callback('q', |s| s.quit());
|
||||
cursive.set_theme(theme::default());
|
||||
cursive.set_autorefresh(true);
|
||||
|
||||
let queue = Arc::new(Mutex::new(queue::Queue::new(event_manager.clone())));
|
||||
|
||||
@@ -131,8 +133,8 @@ fn main() {
|
||||
cursive.add_fullscreen_layer(search.view);
|
||||
|
||||
let queuescreen = cursive.add_active_screen();
|
||||
let mut queue = ui::queue::QueueView::new(queue.clone(), spotify.clone());
|
||||
cursive.add_fullscreen_layer(queue.view.take().unwrap());
|
||||
let mut queueview = ui::queue::QueueView::new(queue.clone(), spotify.clone());
|
||||
cursive.add_fullscreen_layer(queueview.view.take().unwrap());
|
||||
|
||||
let logscreen = cursive.add_active_screen();
|
||||
let logview_scroller = ScrollView::new(logview).scroll_strategy(ScrollStrategy::StickToBottom);
|
||||
@@ -144,10 +146,10 @@ fn main() {
|
||||
});
|
||||
|
||||
{
|
||||
let event_manager = event_manager.clone();
|
||||
let ev = event_manager.clone();
|
||||
cursive.add_global_callback(Key::F2, move |s| {
|
||||
s.set_screen(queuescreen);
|
||||
event_manager.clone().send(Event::QueueUpdate);
|
||||
ev.send(Event::Queue(QueueChange::Show));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -161,7 +163,7 @@ fn main() {
|
||||
for event in event_manager.msg_iter() {
|
||||
trace!("event received");
|
||||
match event {
|
||||
Event::QueueUpdate => queue.redraw(&mut cursive),
|
||||
Event::Queue(ev) => queueview.handle_ev(&mut cursive, ev),
|
||||
Event::Player(state) => spotify.updatestate(state),
|
||||
}
|
||||
}
|
||||
|
||||
19
src/queue.rs
19
src/queue.rs
@@ -10,6 +10,13 @@ pub struct Queue {
|
||||
ev: EventManager,
|
||||
}
|
||||
|
||||
pub enum QueueChange {
|
||||
Dequeue,
|
||||
Enqueue,
|
||||
Remove(usize),
|
||||
Show,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn new(ev: EventManager) -> Queue {
|
||||
Queue {
|
||||
@@ -17,14 +24,11 @@ impl Queue {
|
||||
ev: ev,
|
||||
}
|
||||
}
|
||||
fn send_event(&self) {
|
||||
self.ev.send(Event::QueueUpdate);
|
||||
}
|
||||
pub fn remove(&mut self, index: usize) -> Option<FullTrack> {
|
||||
match self.queue.remove(index) {
|
||||
Some(track) => {
|
||||
debug!("Removed from queue: {}", &track.name);
|
||||
self.send_event();
|
||||
self.ev.send(Event::Queue(QueueChange::Remove(index)));
|
||||
Some(track)
|
||||
}
|
||||
None => None,
|
||||
@@ -33,18 +37,21 @@ impl Queue {
|
||||
pub fn enqueue(&mut self, track: FullTrack) {
|
||||
debug!("Queued: {}", &track.name);
|
||||
self.queue.push_back(track);
|
||||
self.send_event();
|
||||
self.ev.send(Event::Queue(QueueChange::Enqueue));
|
||||
}
|
||||
pub fn dequeue(&mut self) -> Option<FullTrack> {
|
||||
match self.queue.pop_front() {
|
||||
Some(track) => {
|
||||
debug!("Dequeued : {}", track.name);
|
||||
self.send_event();
|
||||
self.ev.send(Event::Queue(QueueChange::Dequeue));
|
||||
Some(track)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
pub fn peek(&self) -> Option<&FullTrack> {
|
||||
self.queue.get(0)
|
||||
}
|
||||
pub fn iter(&self) -> Iter<FullTrack> {
|
||||
self.queue.iter()
|
||||
}
|
||||
|
||||
109
src/ui/queue.rs
109
src/ui/queue.rs
@@ -9,23 +9,23 @@ use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use librespot::core::spotify_id::SpotifyId;
|
||||
use rspotify::spotify::model::track::FullTrack;
|
||||
|
||||
use queue::Queue;
|
||||
use queue::{Queue, QueueChange};
|
||||
use spotify::Spotify;
|
||||
use ui::trackbutton::TrackButton;
|
||||
|
||||
pub struct QueueView {
|
||||
pub view: Option<Panel<LinearLayout>>,
|
||||
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 {
|
||||
let queuelist = ListView::new().with_id("queue_list").full_width();
|
||||
let queuelist = LinearLayout::new(Orientation::Vertical).with_id("queue_list");
|
||||
let scrollable = ScrollView::new(queuelist).full_width().full_height();
|
||||
let layout = LinearLayout::new(Orientation::Vertical).child(scrollable);
|
||||
let panel = Panel::new(layout).title("Queue");
|
||||
let panel = Panel::new(scrollable).title("Queue");
|
||||
|
||||
QueueView {
|
||||
view: Some(panel),
|
||||
@@ -34,32 +34,83 @@ impl QueueView {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redraw(&self, s: &mut Cursive) {
|
||||
let view_ref: Option<ViewRef<ListView>> = s.find_id("queue_list");
|
||||
fn cb_delete(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();
|
||||
queue.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
fn cb_play(cursive: &mut Cursive, queue: &mut Queue, spotify: &Spotify) {
|
||||
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");
|
||||
let trackid = SpotifyId::from_base62(&track.id).expect("could not load track");
|
||||
spotify.load(trackid);
|
||||
spotify.play();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ev(&self, cursive: &mut Cursive, ev: QueueChange) {
|
||||
let view_ref: Option<ViewRef<LinearLayout>> = cursive.find_id("queue_list");
|
||||
if let Some(mut queuelist) = view_ref {
|
||||
queuelist.clear();
|
||||
|
||||
let queue_ref = self.queue.clone();
|
||||
let queue = self.queue.lock().unwrap();
|
||||
for (index, track) in queue.iter().enumerate() {
|
||||
let mut button = TrackButton::new(&track);
|
||||
let spotify = self.spotify.clone();
|
||||
|
||||
// <enter> dequeues the selected track
|
||||
let queue_ref = queue_ref.clone();
|
||||
button.add_callback(Key::Enter, move |_cursive| {
|
||||
let track = queue_ref
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(index)
|
||||
.expect("could not dequeue track");
|
||||
let trackid = SpotifyId::from_base62(&track.id).expect("could not load track");
|
||||
spotify.load(trackid);
|
||||
spotify.play();
|
||||
});
|
||||
|
||||
queuelist.add_child("", button);
|
||||
match ev {
|
||||
QueueChange::Enqueue => {
|
||||
let queue = self.queue.lock().expect("could not lock queue");
|
||||
let track = queue.peek().expect("queue is empty");
|
||||
let button = self.create_button(&track);
|
||||
queuelist.insert_child(0, button);
|
||||
}
|
||||
QueueChange::Dequeue => {
|
||||
queuelist.remove_child(0);
|
||||
}
|
||||
QueueChange::Remove(index) => {
|
||||
queuelist.remove_child(index);
|
||||
}
|
||||
QueueChange::Show => self.populate(&mut queuelist),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_button(&self, track: &FullTrack) -> TrackButton {
|
||||
let mut button = TrackButton::new(&track);
|
||||
// 'd' deletes the selected track
|
||||
{
|
||||
let queue_ref = self.queue.clone();
|
||||
button.add_callback('d', move |cursive| {
|
||||
Self::cb_delete(
|
||||
cursive,
|
||||
&mut queue_ref.lock().expect("could not lock queue"),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// <enter> dequeues 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,
|
||||
);
|
||||
});
|
||||
}
|
||||
button
|
||||
}
|
||||
|
||||
pub fn populate(&self, queuelist: &mut LinearLayout) {
|
||||
while queuelist.len() > 0 {
|
||||
queuelist.remove_child(0);
|
||||
}
|
||||
|
||||
let queue = self.queue.lock().expect("could not lock queue");
|
||||
for track in queue.iter() {
|
||||
let button = self.create_button(&track);
|
||||
queuelist.add_child(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user