musichoard/src/tui/ui/info.rs

112 lines
3.4 KiB
Rust
Raw Normal View History

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 }
}
}