Display saved/followed checkmark
This commit is contained in:
14
src/album.rs
14
src/album.rs
@@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||
use chrono::{DateTime, Utc};
|
||||
use rspotify::spotify::model::album::{FullAlbum, SavedAlbum, SimplifiedAlbum};
|
||||
|
||||
use library::Library;
|
||||
use queue::Queue;
|
||||
use spotify::Spotify;
|
||||
use track::Track;
|
||||
@@ -127,8 +128,17 @@ impl ListItem for Album {
|
||||
format!("{}", self)
|
||||
}
|
||||
|
||||
fn display_right(&self) -> String {
|
||||
self.year.clone()
|
||||
fn display_right(&self, library: Arc<Library>) -> String {
|
||||
let saved = if library.is_saved_album(self) {
|
||||
if library.use_nerdfont {
|
||||
"\u{f62b} "
|
||||
} else {
|
||||
"✓ "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
};
|
||||
format!("{}{}", saved, self.year)
|
||||
}
|
||||
|
||||
fn play(&mut self, queue: Arc<Queue>) {
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||
use rspotify::spotify::model::artist::{FullArtist, SimplifiedArtist};
|
||||
|
||||
use album::Album;
|
||||
use library::Library;
|
||||
use queue::Queue;
|
||||
use spotify::Spotify;
|
||||
use track::Track;
|
||||
@@ -16,6 +17,7 @@ pub struct Artist {
|
||||
pub url: String,
|
||||
pub albums: Option<Vec<Album>>,
|
||||
pub tracks: Option<Vec<Track>>,
|
||||
pub is_followed: bool,
|
||||
}
|
||||
|
||||
impl Artist {
|
||||
@@ -69,6 +71,7 @@ impl From<&SimplifiedArtist> for Artist {
|
||||
url: sa.uri.clone(),
|
||||
albums: None,
|
||||
tracks: None,
|
||||
is_followed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +84,7 @@ impl From<&FullArtist> for Artist {
|
||||
url: fa.uri.clone(),
|
||||
albums: None,
|
||||
tracks: None,
|
||||
is_followed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,13 +122,24 @@ impl ListItem for Artist {
|
||||
format!("{}", self)
|
||||
}
|
||||
|
||||
fn display_right(&self) -> String {
|
||||
// TODO: indicate following status
|
||||
if let Some(tracks) = self.tracks.as_ref() {
|
||||
format!("{} saved tracks", tracks.len())
|
||||
fn display_right(&self, library: Arc<Library>) -> String {
|
||||
let followed = if library.is_followed_artist(self) {
|
||||
if library.use_nerdfont {
|
||||
"\u{f62b} "
|
||||
} else {
|
||||
"✓ "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let tracks = if let Some(tracks) = self.tracks.as_ref() {
|
||||
format!("{:>3} saved tracks", tracks.len())
|
||||
} else {
|
||||
"".into()
|
||||
}
|
||||
};
|
||||
|
||||
format!("{}{}", followed, tracks)
|
||||
}
|
||||
|
||||
fn play(&mut self, queue: Arc<Queue>) {
|
||||
|
||||
@@ -31,10 +31,11 @@ pub struct Library {
|
||||
pub playlists: Arc<RwLock<Vec<Playlist>>>,
|
||||
ev: EventManager,
|
||||
spotify: Arc<Spotify>,
|
||||
pub use_nerdfont: bool,
|
||||
}
|
||||
|
||||
impl Library {
|
||||
pub fn new(ev: &EventManager, spotify: Arc<Spotify>) -> Self {
|
||||
pub fn new(ev: &EventManager, spotify: Arc<Spotify>, use_nerdfont: bool) -> Self {
|
||||
let library = Self {
|
||||
tracks: Arc::new(RwLock::new(Vec::new())),
|
||||
albums: Arc::new(RwLock::new(Vec::new())),
|
||||
@@ -42,6 +43,7 @@ impl Library {
|
||||
playlists: Arc::new(RwLock::new(Vec::new())),
|
||||
ev: ev.clone(),
|
||||
spotify,
|
||||
use_nerdfont,
|
||||
};
|
||||
|
||||
{
|
||||
@@ -303,13 +305,16 @@ impl Library {
|
||||
let mut store = self.artists.write().unwrap();
|
||||
|
||||
for artist in artists.iter_mut() {
|
||||
if store.iter().any(|a| &a.id == &artist.id) {
|
||||
let pos = store.iter().position(|a| &a.id == &artist.id);
|
||||
if let Some(i) = pos {
|
||||
store[i].is_followed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only play saved tracks
|
||||
artist.albums = Some(Vec::new());
|
||||
artist.tracks = Some(Vec::new());
|
||||
artist.is_followed = true;
|
||||
|
||||
store.push(artist.clone());
|
||||
}
|
||||
@@ -463,4 +468,24 @@ impl Library {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_saved_track(&self, track: &Track) -> bool {
|
||||
let tracks = self.tracks.read().unwrap();
|
||||
tracks.iter().any(|t| t.id == track.id)
|
||||
}
|
||||
|
||||
pub fn is_saved_album(&self, album: &Album) -> bool {
|
||||
let albums = self.albums.read().unwrap();
|
||||
albums.iter().any(|a| a.id == album.id)
|
||||
}
|
||||
|
||||
pub fn is_followed_artist(&self, artist: &Artist) -> bool {
|
||||
let artists = self.artists.read().unwrap();
|
||||
artists.iter().any(|a| a.id == artist.id && a.is_followed)
|
||||
}
|
||||
|
||||
pub fn is_saved_playlist(&self, playlist: &Playlist) -> bool {
|
||||
let playlists = self.playlists.read().unwrap();
|
||||
playlists.iter().any(|p| p.id == playlist.id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ fn main() {
|
||||
#[cfg(feature = "mpris")]
|
||||
let mpris_manager = Arc::new(mpris::MprisManager::new(spotify.clone(), queue.clone()));
|
||||
|
||||
let library = Arc::new(Library::new(&event_manager, spotify.clone()));
|
||||
let library = Arc::new(Library::new(&event_manager, spotify.clone(), cfg.use_nerdfont.unwrap_or(false)));
|
||||
|
||||
let mut cmd_manager = CommandManager::new();
|
||||
cmd_manager.register_all(spotify.clone(), queue.clone(), library.clone());
|
||||
@@ -168,7 +168,12 @@ fn main() {
|
||||
cfg.keybindings.clone(),
|
||||
);
|
||||
|
||||
let search = ui::search::SearchView::new(event_manager.clone(), spotify.clone(), queue.clone());
|
||||
let search = ui::search::SearchView::new(
|
||||
event_manager.clone(),
|
||||
spotify.clone(),
|
||||
queue.clone(),
|
||||
library.clone()
|
||||
);
|
||||
|
||||
let libraryview = ui::library::LibraryView::new(queue.clone(), library.clone());
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::iter::Iterator;
|
||||
use std::sync::Arc;
|
||||
|
||||
use queue::Queue;
|
||||
use library::Library;
|
||||
use track::Track;
|
||||
use traits::ListItem;
|
||||
|
||||
@@ -30,8 +31,17 @@ impl ListItem for Playlist {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn display_right(&self) -> String {
|
||||
format!("{} tracks", self.tracks.len())
|
||||
fn display_right(&self, library: Arc<Library>) -> String {
|
||||
let saved = if library.is_saved_playlist(self) {
|
||||
if library.use_nerdfont {
|
||||
"\u{f62b} "
|
||||
} else {
|
||||
"✓ "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
};
|
||||
format!("{}{:>3} tracks", saved, self.tracks.len())
|
||||
}
|
||||
|
||||
fn play(&mut self, queue: Arc<Queue>) {
|
||||
|
||||
14
src/track.rs
14
src/track.rs
@@ -5,6 +5,7 @@ use chrono::{DateTime, Utc};
|
||||
use rspotify::spotify::model::album::FullAlbum;
|
||||
use rspotify::spotify::model::track::{FullTrack, SavedTrack, SimplifiedTrack};
|
||||
|
||||
use library::Library;
|
||||
use queue::Queue;
|
||||
use traits::ListItem;
|
||||
|
||||
@@ -147,8 +148,17 @@ impl ListItem for Track {
|
||||
format!("{}", self)
|
||||
}
|
||||
|
||||
fn display_right(&self) -> String {
|
||||
self.duration_str()
|
||||
fn display_right(&self, library: Arc<Library>) -> String {
|
||||
let saved = if library.is_saved_track(self) {
|
||||
if library.use_nerdfont {
|
||||
"\u{f62b} "
|
||||
} else {
|
||||
"✓ "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
};
|
||||
format!("{}{}", saved, self.duration_str())
|
||||
}
|
||||
|
||||
fn play(&mut self, queue: Arc<Queue>) {
|
||||
|
||||
@@ -5,12 +5,13 @@ use cursive::views::IdView;
|
||||
use cursive::Cursive;
|
||||
|
||||
use commands::CommandResult;
|
||||
use library::Library;
|
||||
use queue::Queue;
|
||||
|
||||
pub trait ListItem: Sync + Send + 'static {
|
||||
fn is_playing(&self, queue: Arc<Queue>) -> bool;
|
||||
fn display_left(&self) -> String;
|
||||
fn display_right(&self) -> String;
|
||||
fn display_right(&self, library: Arc<Library>) -> String;
|
||||
fn play(&mut self, queue: Arc<Queue>);
|
||||
fn queue(&mut self, queue: Arc<Queue>);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ pub struct LibraryView {
|
||||
impl LibraryView {
|
||||
pub fn new(queue: Arc<Queue>, library: Arc<Library>) -> Self {
|
||||
let tabs = TabView::new()
|
||||
.tab("tracks", "Tracks", ListView::new(library.tracks.clone(), queue.clone()))
|
||||
.tab("albums", "Albums", ListView::new(library.albums.clone(), queue.clone()))
|
||||
.tab("artists", "Artists", ListView::new(library.artists.clone(), queue.clone()))
|
||||
.tab("tracks", "Tracks", ListView::new(library.tracks.clone(), queue.clone(), library.clone()))
|
||||
.tab("albums", "Albums", ListView::new(library.albums.clone(), queue.clone(), library.clone()))
|
||||
.tab("artists", "Artists", ListView::new(library.artists.clone(), queue.clone(), library.clone()))
|
||||
.tab("playlists", "Playlists", PlaylistsView::new(queue.clone(), library.clone()));
|
||||
|
||||
Self {
|
||||
|
||||
@@ -10,6 +10,7 @@ use cursive::{Cursive, Printer, Rect, Vec2};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use commands::CommandResult;
|
||||
use library::Library;
|
||||
use queue::Queue;
|
||||
use track::Track;
|
||||
use traits::{ListItem, ViewExt};
|
||||
@@ -84,11 +85,12 @@ pub struct ListView<I: ListItem> {
|
||||
last_size: Vec2,
|
||||
scrollbar: ScrollBase,
|
||||
queue: Arc<Queue>,
|
||||
library: Arc<Library>,
|
||||
pagination: Pagination<I>,
|
||||
}
|
||||
|
||||
impl<I: ListItem> ListView<I> {
|
||||
pub fn new(content: Arc<RwLock<Vec<I>>>, queue: Arc<Queue>) -> Self {
|
||||
pub fn new(content: Arc<RwLock<Vec<I>>>, queue: Arc<Queue>, library: Arc<Library>) -> Self {
|
||||
Self {
|
||||
content,
|
||||
last_content_len: 0,
|
||||
@@ -96,6 +98,7 @@ impl<I: ListItem> ListView<I> {
|
||||
last_size: Vec2::new(0, 0),
|
||||
scrollbar: ScrollBase::new(),
|
||||
queue,
|
||||
library,
|
||||
pagination: Pagination::default(),
|
||||
}
|
||||
}
|
||||
@@ -174,7 +177,7 @@ impl<I: ListItem> View for ListView<I> {
|
||||
};
|
||||
|
||||
let left = item.display_left();
|
||||
let right = item.display_right();
|
||||
let right = item.display_right(self.library.clone());
|
||||
|
||||
// draw left string
|
||||
printer.with_color(style, |printer| {
|
||||
|
||||
@@ -20,7 +20,7 @@ pub struct PlaylistsView {
|
||||
impl PlaylistsView {
|
||||
pub fn new(queue: Arc<Queue>, library: Arc<Library>) -> Self {
|
||||
Self {
|
||||
list: ListView::new(library.playlists.clone(), queue.clone()),
|
||||
list: ListView::new(library.playlists.clone(), queue.clone(), library.clone()),
|
||||
library,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ pub struct QueueView {
|
||||
|
||||
impl QueueView {
|
||||
pub fn new(queue: Arc<Queue>, library: Arc<Library>) -> QueueView {
|
||||
let list = ListView::new(queue.queue.clone(), queue.clone());
|
||||
let list = ListView::new(queue.queue.clone(), queue.clone(), library.clone());
|
||||
|
||||
QueueView {
|
||||
list,
|
||||
|
||||
@@ -44,7 +44,12 @@ type SearchHandler<I> =
|
||||
pub const LIST_ID: &str = "search_list";
|
||||
pub const EDIT_ID: &str = "search_edit";
|
||||
impl SearchView {
|
||||
pub fn new(events: EventManager, spotify: Arc<Spotify>, queue: Arc<Queue>) -> SearchView {
|
||||
pub fn new(
|
||||
events: EventManager,
|
||||
spotify: Arc<Spotify>,
|
||||
queue: Arc<Queue>,
|
||||
library: Arc<Library>
|
||||
) -> SearchView {
|
||||
let results_tracks = Arc::new(RwLock::new(Vec::new()));
|
||||
let results_albums = Arc::new(RwLock::new(Vec::new()));
|
||||
let results_artists = Arc::new(RwLock::new(Vec::new()));
|
||||
@@ -61,13 +66,13 @@ impl SearchView {
|
||||
})
|
||||
.with_id(EDIT_ID);
|
||||
|
||||
let list_tracks = ListView::new(results_tracks.clone(), queue.clone());
|
||||
let list_tracks = ListView::new(results_tracks.clone(), queue.clone(), library.clone());
|
||||
let pagination_tracks = list_tracks.get_pagination().clone();
|
||||
let list_albums = ListView::new(results_albums.clone(), queue.clone());
|
||||
let list_albums = ListView::new(results_albums.clone(), queue.clone(), library.clone());
|
||||
let pagination_albums = list_albums.get_pagination().clone();
|
||||
let list_artists = ListView::new(results_artists.clone(), queue.clone());
|
||||
let list_artists = ListView::new(results_artists.clone(), queue.clone(), library.clone());
|
||||
let pagination_artists = list_artists.get_pagination().clone();
|
||||
let list_playlists = ListView::new(results_playlists.clone(), queue.clone());
|
||||
let list_playlists = ListView::new(results_playlists.clone(), queue.clone(), library.clone());
|
||||
let pagination_playlists = list_playlists.get_pagination().clone();
|
||||
|
||||
let tabs = TabView::new()
|
||||
|
||||
Reference in New Issue
Block a user