use std::collections::HashMap; use musichoard::collection::{album::Album, artist::Artist, musicbrainz::IMusicBrainzRef}; use ratatui::widgets::{ListState, Paragraph}; struct InfoOverlay; impl InfoOverlay { const ITEM_INDENT: &'static str = " "; const LIST_INDENT: &'static str = " - "; } pub struct ArtistOverlay<'a> { pub properties: Paragraph<'a>, } impl<'a> ArtistOverlay<'a> { fn opt_hashmap_to_string, T: AsRef>( opt_map: Option<&HashMap>>, item_indent: &str, list_indent: &str, ) -> String { opt_map .map(|map| Self::hashmap_to_string(map, item_indent, list_indent)) .unwrap_or_else(|| String::from("")) } fn hashmap_to_string, T: AsRef>( map: &HashMap>, item_indent: &str, list_indent: &str, ) -> String { let mut vec: Vec<(&str, &Vec)> = map.iter().map(|(k, v)| (k.as_ref(), v)).collect(); vec.sort_by(|x, y| x.0.cmp(y.0)); let indent = format!("\n{item_indent}"); let list = vec .iter() .map(|(k, v)| format!("{k}: {}", Self::slice_to_string(v, list_indent))) .collect::>() .join(&indent); format!("{indent}{list}") } fn slice_to_string>(vec: &[S], indent: &str) -> String { if vec.len() < 2 { vec.first() .map(|item| item.as_ref()) .unwrap_or("") .to_string() } else { let indent = format!("\n{indent}"); let list = vec .iter() .map(|item| item.as_ref()) .collect::>() .join(&indent); format!("{indent}{list}") } } pub fn new(artists: &'a [Artist], state: &ListState) -> ArtistOverlay<'a> { let artist = state.selected().map(|i| &artists[i]); let item_indent = InfoOverlay::ITEM_INDENT; let list_indent = InfoOverlay::LIST_INDENT; let double_item_indent = format!("{item_indent}{item_indent}"); let double_list_indent = format!("{item_indent}{list_indent}"); let properties = Paragraph::new(format!( "Artist: {}\n\n{item_indent}\ MusicBrainz: {}\n{item_indent}\ Properties: {}", artist.map(|a| a.meta.id.name.as_str()).unwrap_or(""), artist .and_then(|a| a.meta.musicbrainz.as_ref().map(|mb| mb.url().as_str())) .unwrap_or(""), Self::opt_hashmap_to_string( artist.map(|a| &a.meta.properties), &double_item_indent, &double_list_indent ), )); ArtistOverlay { properties } } } pub struct AlbumOverlay<'a> { pub properties: Paragraph<'a>, } impl<'a> AlbumOverlay<'a> { pub fn new(albums: &'a [Album], state: &ListState) -> AlbumOverlay<'a> { let album = state.selected().map(|i| &albums[i]); let item_indent = InfoOverlay::ITEM_INDENT; let properties = Paragraph::new(format!( "Album: {}\n\n{item_indent}\ MusicBrainz: {}", album.map(|a| a.meta.id.title.as_str()).unwrap_or(""), album .and_then(|a| a.meta.musicbrainz.as_ref().map(|mb| mb.url().as_str())) .unwrap_or(""), )); AlbumOverlay { properties } } }