add methods and api usage to delete track from playlist (#211)
* wip: add methods and api usage to delete track from playlist * enh: add ability to remove track from playlist with immediate visual feedback * minor cosmetic changes Co-authored-by: Henrik Friedrichsen <henrik@affekt.org>
This commit is contained in:
@@ -51,6 +51,16 @@ impl Playlist {
|
|||||||
|
|
||||||
self.tracks = Some(collected_tracks);
|
self.tracks = Some(collected_tracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete_tracks(&mut self, track_pos_pairs: &[(Track, usize)], spotify: Arc<Spotify>) {
|
||||||
|
if spotify.delete_tracks(&self.id, track_pos_pairs) {
|
||||||
|
if let Some(tracks) = &mut self.tracks {
|
||||||
|
for (_track, pos) in track_pos_pairs {
|
||||||
|
tracks.remove(*pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&SimplifiedPlaylist> for Playlist {
|
impl From<&SimplifiedPlaylist> for Playlist {
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ use rspotify::spotify::model::search::{
|
|||||||
use rspotify::spotify::model::track::{FullTrack, SavedTrack};
|
use rspotify::spotify::model::track::{FullTrack, SavedTrack};
|
||||||
use rspotify::spotify::model::user::PrivateUser;
|
use rspotify::spotify::model::user::PrivateUser;
|
||||||
|
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
use futures_01::future::Future as v01_Future;
|
use futures_01::future::Future as v01_Future;
|
||||||
@@ -566,6 +568,27 @@ impl Spotify {
|
|||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete_tracks(&self, playlist_id: &str, track_pos_pairs: &[(Track, usize)]) -> bool {
|
||||||
|
let mut tracks = Vec::new();
|
||||||
|
for (track, pos) in track_pos_pairs {
|
||||||
|
let track_occurrence = json!({
|
||||||
|
"uri": format!("spotify:track:{}", track.id.clone().unwrap()),
|
||||||
|
"positions": [pos]
|
||||||
|
});
|
||||||
|
let track_occurrence_object = track_occurrence.as_object();
|
||||||
|
tracks.push(track_occurrence_object.unwrap().clone());
|
||||||
|
}
|
||||||
|
self.api_with_retry(|api| {
|
||||||
|
api.user_playlist_remove_specific_occurrenes_of_tracks(
|
||||||
|
self.user.as_ref().unwrap(),
|
||||||
|
playlist_id,
|
||||||
|
tracks.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn overwrite_playlist(&self, id: &str, tracks: &[Track]) {
|
pub fn overwrite_playlist(&self, id: &str, tracks: &[Track]) {
|
||||||
// extract only track IDs
|
// extract only track IDs
|
||||||
let mut tracks: Vec<String> = tracks
|
let mut tracks: Vec<String> = tracks
|
||||||
|
|||||||
@@ -154,6 +154,11 @@ impl<I: ListItem> ListView<I> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove(&self, index: usize) {
|
||||||
|
let mut c = self.content.write().unwrap();
|
||||||
|
c.remove(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: ListItem> View for ListView<I> {
|
impl<I: ListItem> View for ListView<I> {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::commands::CommandResult;
|
|||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::playlist::Playlist;
|
use crate::playlist::Playlist;
|
||||||
use crate::queue::Queue;
|
use crate::queue::Queue;
|
||||||
|
use crate::spotify::Spotify;
|
||||||
use crate::track::Track;
|
use crate::track::Track;
|
||||||
use crate::traits::ViewExt;
|
use crate::traits::ViewExt;
|
||||||
use crate::ui::listview::ListView;
|
use crate::ui::listview::ListView;
|
||||||
@@ -15,12 +16,12 @@ use crate::ui::listview::ListView;
|
|||||||
pub struct PlaylistView {
|
pub struct PlaylistView {
|
||||||
playlist: Playlist,
|
playlist: Playlist,
|
||||||
list: ListView<Track>,
|
list: ListView<Track>,
|
||||||
|
spotify: Arc<Spotify>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistView {
|
impl PlaylistView {
|
||||||
pub fn new(queue: Arc<Queue>, library: Arc<Library>, playlist: &Playlist) -> Self {
|
pub fn new(queue: Arc<Queue>, library: Arc<Library>, playlist: &Playlist) -> Self {
|
||||||
let mut playlist = playlist.clone();
|
let mut playlist = playlist.clone();
|
||||||
|
|
||||||
playlist.load_tracks(queue.get_spotify());
|
playlist.load_tracks(queue.get_spotify());
|
||||||
|
|
||||||
let tracks = if let Some(t) = playlist.tracks.as_ref() {
|
let tracks = if let Some(t) = playlist.tracks.as_ref() {
|
||||||
@@ -29,9 +30,14 @@ impl PlaylistView {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let spotify = queue.get_spotify();
|
||||||
let list = ListView::new(Arc::new(RwLock::new(tracks)), queue, library);
|
let list = ListView::new(Arc::new(RwLock::new(tracks)), queue, library);
|
||||||
|
|
||||||
Self { playlist, list }
|
Self {
|
||||||
|
playlist,
|
||||||
|
list,
|
||||||
|
spotify,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +51,22 @@ impl ViewExt for PlaylistView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
|
||||||
|
if let Command::Delete = cmd {
|
||||||
|
let pos = self.list.get_selected_index();
|
||||||
|
let tracks = if let Some(t) = self.playlist.tracks.as_ref() {
|
||||||
|
t.clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
let track = tracks.get(pos);
|
||||||
|
if let Some(t) = track {
|
||||||
|
self.playlist
|
||||||
|
.delete_tracks(&[(t.clone(), pos)], self.spotify.clone());
|
||||||
|
self.list.remove(pos);
|
||||||
|
}
|
||||||
|
return Ok(CommandResult::Consumed(None));
|
||||||
|
}
|
||||||
|
|
||||||
self.list.on_command(s, cmd)
|
self.list.on_command(s, cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user