112 lines
3.4 KiB
Rust
112 lines
3.4 KiB
Rust
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<K: Ord + AsRef<str>, T: AsRef<str>>(
|
|
opt_map: Option<&HashMap<K, Vec<T>>>,
|
|
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<K: AsRef<str>, T: AsRef<str>>(
|
|
map: &HashMap<K, Vec<T>>,
|
|
item_indent: &str,
|
|
list_indent: &str,
|
|
) -> String {
|
|
let mut vec: Vec<(&str, &Vec<T>)> = 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::<Vec<String>>()
|
|
.join(&indent);
|
|
format!("{indent}{list}")
|
|
}
|
|
|
|
fn slice_to_string<S: AsRef<str>>(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::<Vec<&str>>()
|
|
.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 }
|
|
}
|
|
}
|