From 5fb4eb7af2b29a4c5f7d8a288b702a9bef982614 Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Sun, 25 Oct 2020 00:09:23 +0200 Subject: [PATCH] fix: update playlist changes in local store Move playlist change logic out of the library while we're at it and notify the library of changes instead. fixes #302 --- src/library.rs | 37 +++++------------------------------ src/main.rs | 1 - src/mpris.rs | 4 ++-- src/playlist.rs | 45 +++++++++++++++++++++++++++++++++++++++++-- src/ui/contextmenu.rs | 39 +++++++++++++++++++++++++------------ src/ui/playlist.rs | 11 ++++++++--- 6 files changed, 85 insertions(+), 52 deletions(-) diff --git a/src/library.rs b/src/library.rs index 960fbf3..d584ed3 100644 --- a/src/library.rs +++ b/src/library.rs @@ -523,41 +523,14 @@ impl Library { } } - // Return true if the given playlist contains the given track - pub fn playlist_has_track(&self, playlist_id: &str, track_id: &str) -> bool { - let playlists = self.playlists.read().expect("can't readlock playlists"); - if let Some(playlist) = playlists.iter().find(|p| p.id == playlist_id) { - playlist.tracks.as_ref().map_or(false, |tracks| { - tracks.iter().any(|t| t.id == Some(track_id.to_string())) - }) - } else { - false - } - } - - pub fn playlist_append_tracks(&self, playlist_id: &str, new_tracks: &[Track]) { - let track_ids: Vec = new_tracks - .to_vec() - .iter() - .filter(|t| t.id.is_some()) - .map(|t| t.id.clone().unwrap()) - .collect(); - - let mut has_modified = false; - - if self.spotify.append_tracks(playlist_id, &track_ids, None) { + pub fn playlist_update(&self, updated: &Playlist) { + { let mut playlists = self.playlists.write().expect("can't writelock playlists"); - if let Some(playlist) = playlists.iter_mut().find(|p| p.id == playlist_id) { - if let Some(tracks) = &mut playlist.tracks { - tracks.append(&mut new_tracks.to_vec()); - has_modified = true; - } + if let Some(playlist) = playlists.iter_mut().find(|p| p.id == updated.id) { + *playlist = updated.clone(); } } - - if has_modified { - self.save_cache(config::cache_path(CACHE_PLAYLISTS), self.playlists.clone()); - } + self.save_cache(config::cache_path(CACHE_PLAYLISTS), self.playlists.clone()); } pub fn is_saved_track(&self, track: &Playable) -> bool { diff --git a/src/main.rs b/src/main.rs index 2d083bb..6378693 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,6 @@ extern crate tokio_timer; extern crate unicode_width; extern crate webbrowser; - #[macro_use] extern crate serde; extern crate serde_json; diff --git a/src/mpris.rs b/src/mpris.rs index 00a9134..34742bf 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -1,5 +1,5 @@ -extern crate dbus_tree; extern crate dbus; +extern crate dbus_tree; use std::collections::HashMap; use std::rc::Rc; @@ -9,8 +9,8 @@ use std::time::Duration; use dbus::arg::{RefArg, Variant}; use dbus::ffidisp::stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged; use dbus::message::SignalArgs; -use dbus_tree::{Access, Factory}; use dbus::strings::Path; +use dbus_tree::{Access, Factory}; use crate::album::Album; use crate::episode::Episode; diff --git a/src/playlist.rs b/src/playlist.rs index 4bc4f63..9f029e2 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -30,7 +30,7 @@ impl Playlist { self.tracks = Some(self.get_all_tracks(spotify)); } - pub fn get_all_tracks(&self, spotify: Arc) -> Vec { + fn get_all_tracks(&self, spotify: Arc) -> Vec { let mut collected_tracks = Vec::new(); let mut tracks_result = spotify.user_playlist_tracks(&self.id, 100, 0); @@ -59,15 +59,56 @@ impl Playlist { collected_tracks } - pub fn delete_tracks(&mut self, track_pos_pairs: &[(Track, usize)], spotify: Arc) { + pub fn has_track(&self, track_id: &str) -> bool { + self.tracks.as_ref().map_or(false, |tracks| { + tracks + .iter() + .any(|track| track.id == Some(track_id.to_string())) + }) + } + + pub fn delete_tracks( + &mut self, + track_pos_pairs: &[(Track, usize)], + spotify: Arc, + library: Arc, + ) { 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); } + library.playlist_update(&self); } } } + + pub fn append_tracks( + &mut self, + new_tracks: &[Track], + spotify: Arc, + library: Arc, + ) { + let track_ids: Vec = new_tracks + .to_vec() + .iter() + .filter(|t| t.id.is_some()) + .map(|t| t.id.clone().unwrap()) + .collect(); + + let mut has_modified = false; + + if spotify.append_tracks(&self.id, &track_ids, None) { + if let Some(tracks) = &mut self.tracks { + tracks.append(&mut new_tracks.to_vec()); + has_modified = true; + } + } + + if has_modified { + library.playlist_update(self); + } + } } impl From<&SimplifiedPlaylist> for Playlist { diff --git a/src/ui/contextmenu.rs b/src/ui/contextmenu.rs index eb83fab..ee0ffe8 100644 --- a/src/ui/contextmenu.rs +++ b/src/ui/contextmenu.rs @@ -4,7 +4,6 @@ use cursive::view::{Margins, ViewWrapper}; use cursive::views::{Dialog, NamedView, ScrollView, SelectView}; use cursive::Cursive; -use crate::command::{Command, MoveAmount, MoveMode}; use crate::commands::CommandResult; use crate::library::Library; use crate::queue::Queue; @@ -12,6 +11,11 @@ use crate::track::Track; use crate::traits::{ListItem, ViewExt}; use crate::ui::layout::Layout; use crate::ui::modal::Modal; +use crate::{ + command::{Command, MoveAmount, MoveMode}, + playlist::Playlist, + spotify::Spotify, +}; #[cfg(feature = "share_clipboard")] use clipboard::{ClipboardContext, ClipboardProvider}; use cursive::traits::{Finder, Nameable}; @@ -28,23 +32,33 @@ enum ContextMenuAction { } impl ContextMenu { - pub fn add_track_dialog(library: Arc, track: Track) -> Modal { - let mut list_select: SelectView = SelectView::new().autojump(); + pub fn add_track_dialog( + library: Arc, + spotify: Arc, + track: Track, + ) -> Modal { + let mut list_select: SelectView = SelectView::new().autojump(); for list in library.items().iter() { - list_select.add_item(list.name.clone(), list.id.clone()); + list_select.add_item(list.name.clone(), list.clone()); } list_select.set_on_submit(move |s, selected| { let track = track.clone(); + let mut playlist = selected.clone(); + let spotify = spotify.clone(); + let library = library.clone(); - if library.playlist_has_track(selected, &track.id.as_ref().unwrap_or(&"".to_string())) { + if playlist.has_track(track.id.as_ref().unwrap_or(&String::new())) { let mut already_added_dialog = Self::track_already_added(); - let lib = Arc::clone(&library); - let selected = selected.to_string(); already_added_dialog.add_button("Add anyway", move |c| { - lib.playlist_append_tracks(&selected.clone(), &[track.clone()]); + let mut playlist = playlist.clone(); + let spotify = spotify.clone(); + let library = library.clone(); + + playlist.append_tracks(&[track.clone()], spotify, library); + // playlist.map(|p| p.append_tracks(&[track.clone()], spotify, library)); c.pop_layer(); // Close add_track_dialog too @@ -55,10 +69,10 @@ impl ContextMenu { s.add_layer(modal); return; + } else { + playlist.append_tracks(&[track.clone()], spotify, library); + s.pop_layer(); } - - library.playlist_append_tracks(selected, &[track]); - s.pop_layer(); }); let dialog = Dialog::new() @@ -118,7 +132,8 @@ impl ContextMenu { .ok(); } ContextMenuAction::AddToPlaylist(track) => { - let dialog = Self::add_track_dialog(library, *track.clone()); + let dialog = + Self::add_track_dialog(library, queue.get_spotify(), *track.clone()); s.add_layer(dialog); } ContextMenuAction::ShowRecommentations(item) => { diff --git a/src/ui/playlist.rs b/src/ui/playlist.rs index ece9a15..fa28f40 100644 --- a/src/ui/playlist.rs +++ b/src/ui/playlist.rs @@ -17,6 +17,7 @@ pub struct PlaylistView { playlist: Playlist, list: ListView, spotify: Arc, + library: Arc, } impl PlaylistView { @@ -31,12 +32,13 @@ impl PlaylistView { }; 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.clone()); Self { playlist, list, spotify, + library, } } } @@ -60,8 +62,11 @@ impl ViewExt for PlaylistView { }; let track = tracks.get(pos); if let Some(t) = track { - self.playlist - .delete_tracks(&[(t.clone(), pos)], self.spotify.clone()); + self.playlist.delete_tracks( + &[(t.clone(), pos)], + self.spotify.clone(), + self.library.clone(), + ); self.list.remove(pos); } return Ok(CommandResult::Consumed(None));