Make fetch also fetch artist MBID if it is missing #201
@ -257,9 +257,9 @@ mod tests {
|
|||||||
|
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(public_matches.matches.as_ref().unwrap().matching, &album_1);
|
assert_eq!(public_matches.matches.as_ref().unwrap().album_ref().matching, &album_1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().list,
|
public_matches.matches.as_ref().unwrap().album_ref().list,
|
||||||
matches_1.as_slice()
|
matches_1.as_slice()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -270,9 +270,9 @@ mod tests {
|
|||||||
|
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(public_matches.matches.as_ref().unwrap().matching, &album_4);
|
assert_eq!(public_matches.matches.as_ref().unwrap().album_ref().matching, &album_4);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().list,
|
public_matches.matches.as_ref().unwrap().album_ref().list,
|
||||||
matches_4.as_slice()
|
matches_4.as_slice()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ use musichoard::collection::album::Album;
|
|||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{
|
app::{
|
||||||
machine::{App, AppInner, AppMachine},
|
machine::{App, AppInner, AppMachine},
|
||||||
AppPublic, AppPublicAlbumMatches, AppPublicMatches, AppState, IAppInteractMatches,
|
AppPublic, AppPublicAlbumMatches, AppPublicMatches, AppPublicMatchesKind, AppState,
|
||||||
WidgetState,
|
IAppInteractMatches, WidgetState,
|
||||||
},
|
},
|
||||||
lib::interface::musicbrainz::Match,
|
lib::interface::musicbrainz::Match,
|
||||||
};
|
};
|
||||||
@ -53,9 +53,11 @@ impl From<AppMachine<AppMatches>> for App {
|
|||||||
|
|
||||||
impl<'a> From<&'a mut AppMachine<AppMatches>> for AppPublic<'a> {
|
impl<'a> From<&'a mut AppMachine<AppMatches>> for AppPublic<'a> {
|
||||||
fn from(machine: &'a mut AppMachine<AppMatches>) -> Self {
|
fn from(machine: &'a mut AppMachine<AppMatches>) -> Self {
|
||||||
let matches = machine.state.index.map(|index| AppPublicAlbumMatches {
|
let matches = machine.state.index.map(|index| {
|
||||||
matching: &machine.state.matches_info_vec[index].matching,
|
AppPublicMatchesKind::Album(AppPublicAlbumMatches {
|
||||||
list: machine.state.matches_info_vec[index].matches.as_slice(),
|
matching: &machine.state.matches_info_vec[index].matching,
|
||||||
|
list: machine.state.matches_info_vec[index].matches.as_slice(),
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
AppPublic {
|
AppPublic {
|
||||||
@ -217,11 +219,11 @@ mod tests {
|
|||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().matching,
|
public_matches.matches.as_ref().unwrap().album_ref().matching,
|
||||||
&matches_info_vec[0].matching
|
&matches_info_vec[0].matching
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
public_matches.matches.as_ref().unwrap().list,
|
public_matches.matches.as_ref().unwrap().album_ref().list,
|
||||||
matches_info_vec[0].matches.as_slice()
|
matches_info_vec[0].matches.as_slice()
|
||||||
);
|
);
|
||||||
assert_eq!(public_matches.state, &widget_state);
|
assert_eq!(public_matches.state, &widget_state);
|
||||||
|
@ -4,7 +4,7 @@ mod selection;
|
|||||||
pub use machine::App;
|
pub use machine::App;
|
||||||
pub use selection::{Category, Delta, Selection, WidgetState};
|
pub use selection::{Category, Delta, Selection, WidgetState};
|
||||||
|
|
||||||
use musichoard::collection::{album::Album, Collection};
|
use musichoard::collection::{album::Album, artist::Artist, Collection};
|
||||||
|
|
||||||
use crate::tui::lib::interface::musicbrainz::Match;
|
use crate::tui::lib::interface::musicbrainz::Match;
|
||||||
|
|
||||||
@ -129,14 +129,42 @@ pub struct AppPublicInner<'app> {
|
|||||||
pub selection: &'app mut Selection,
|
pub selection: &'app mut Selection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct AppPublicArtistMatches<'app> {
|
||||||
|
pub matching: &'app Artist,
|
||||||
|
pub list: &'app [Match<Artist>],
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct AppPublicAlbumMatches<'app> {
|
pub struct AppPublicAlbumMatches<'app> {
|
||||||
pub matching: &'app Album,
|
pub matching: &'app Album,
|
||||||
pub list: &'app [Match<Album>],
|
pub list: &'app [Match<Album>],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum AppPublicMatchesKind<'app> {
|
||||||
|
Artist(AppPublicArtistMatches<'app>),
|
||||||
|
Album(AppPublicAlbumMatches<'app>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'app> AppPublicMatchesKind<'app> {
|
||||||
|
pub fn artist_ref(&self) -> &AppPublicArtistMatches<'app> {
|
||||||
|
match self {
|
||||||
|
AppPublicMatchesKind::Artist(m) => m,
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn album_ref(&self) -> &AppPublicAlbumMatches<'app> {
|
||||||
|
match self {
|
||||||
|
AppPublicMatchesKind::Album(m) => m,
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AppPublicMatches<'app> {
|
pub struct AppPublicMatches<'app> {
|
||||||
pub matches: Option<AppPublicAlbumMatches<'app>>,
|
pub matches: Option<AppPublicMatchesKind<'app>>,
|
||||||
pub state: &'app mut WidgetState,
|
pub state: &'app mut WidgetState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::{Album, AlbumDate, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq, AlbumStatus},
|
album::{Album, AlbumDate, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq, AlbumStatus},
|
||||||
|
artist::Artist,
|
||||||
track::{TrackFormat, TrackQuality},
|
track::{TrackFormat, TrackQuality},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::tui::lib::interface::musicbrainz::Match;
|
use crate::tui::{app::AppPublicMatchesKind, lib::interface::musicbrainz::Match};
|
||||||
|
|
||||||
pub struct UiDisplay;
|
pub struct UiDisplay;
|
||||||
|
|
||||||
@ -97,18 +98,37 @@ impl UiDisplay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_matching_info(matching: Option<&Album>) -> String {
|
pub fn display_artist_matching_info(artist: &Artist) -> String {
|
||||||
match matching {
|
format!("Matching artist: {}", &artist.id.name)
|
||||||
Some(matching) => format!(
|
}
|
||||||
"Matching: {} | {}",
|
|
||||||
UiDisplay::display_album_date(&matching.date),
|
pub fn display_album_matching_info(album: &Album) -> String {
|
||||||
&matching.id.title
|
format!(
|
||||||
),
|
"Matching album: {} | {}",
|
||||||
None => String::from("Matching: nothing"),
|
UiDisplay::display_album_date(&album.date),
|
||||||
|
&album.id.title
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_matching_nothing_info() -> &'static str {
|
||||||
|
"Matching nothing"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_matching_info(matches: Option<&AppPublicMatchesKind>) -> String {
|
||||||
|
match matches.as_ref() {
|
||||||
|
Some(kind) => match kind {
|
||||||
|
AppPublicMatchesKind::Artist(m) => {
|
||||||
|
UiDisplay::display_artist_matching_info(m.matching)
|
||||||
|
}
|
||||||
|
AppPublicMatchesKind::Album(m) => {
|
||||||
|
UiDisplay::display_album_matching_info(m.matching)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => UiDisplay::display_matching_nothing_info().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_match_string(match_album: &Match<Album>) -> String {
|
pub fn display_album_match_string(match_album: &Match<Album>) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{:010} | {} [{}] ({}%)",
|
"{:010} | {} [{}] ({}%)",
|
||||||
UiDisplay::display_album_date(&match_album.item.date),
|
UiDisplay::display_album_date(&match_album.item.date),
|
||||||
@ -120,6 +140,17 @@ impl UiDisplay {
|
|||||||
match_album.score,
|
match_album.score,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn display_artist_match_string(match_artist: &Match<Artist>) -> String {
|
||||||
|
let disambiguation_string = match match_artist.disambiguation.as_ref() {
|
||||||
|
Some(d) => format!(" ({d})"),
|
||||||
|
None => String::from(""),
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"{}{} ({}%)",
|
||||||
|
&match_artist.item.id.name, &disambiguation_string, match_artist.score,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,23 +1,42 @@
|
|||||||
use musichoard::collection::album::Album;
|
use musichoard::collection::{album::Album, artist::Artist};
|
||||||
use ratatui::widgets::{List, ListItem};
|
use ratatui::widgets::{List, ListItem};
|
||||||
|
|
||||||
use crate::tui::{app::WidgetState, lib::interface::musicbrainz::Match, ui::display::UiDisplay};
|
use crate::tui::{app::WidgetState, lib::interface::musicbrainz::Match, ui::display::UiDisplay};
|
||||||
|
|
||||||
pub struct AlbumMatchesState<'a, 'b> {
|
pub struct MatchesState<'a, 'b> {
|
||||||
pub list: List<'a>,
|
pub list: List<'a>,
|
||||||
pub state: &'b mut WidgetState,
|
pub state: &'b mut WidgetState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> AlbumMatchesState<'a, 'b> {
|
impl<'a, 'b> MatchesState<'a, 'b> {
|
||||||
pub fn new(matches: &[Match<Album>], state: &'b mut WidgetState) -> Self {
|
pub fn empty(state: &'b mut WidgetState) -> Self {
|
||||||
|
MatchesState {
|
||||||
|
list: List::default(),
|
||||||
|
state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn artists(matches: &[Match<Artist>], state: &'b mut WidgetState) -> Self {
|
||||||
let list = List::new(
|
let list = List::new(
|
||||||
matches
|
matches
|
||||||
.iter()
|
.iter()
|
||||||
.map(UiDisplay::display_match_string)
|
.map(UiDisplay::display_artist_match_string)
|
||||||
.map(ListItem::new)
|
.map(ListItem::new)
|
||||||
.collect::<Vec<ListItem>>(),
|
.collect::<Vec<ListItem>>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
AlbumMatchesState { list, state }
|
MatchesState { list, state }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn albums(matches: &[Match<Album>], state: &'b mut WidgetState) -> Self {
|
||||||
|
let list = List::new(
|
||||||
|
matches
|
||||||
|
.iter()
|
||||||
|
.map(UiDisplay::display_album_match_string)
|
||||||
|
.map(ListItem::new)
|
||||||
|
.collect::<Vec<ListItem>>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
MatchesState { list, state }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,7 @@ impl Minibuffer<'_> {
|
|||||||
},
|
},
|
||||||
AppState::Matches(public) => Minibuffer {
|
AppState::Matches(public) => Minibuffer {
|
||||||
paragraphs: vec![
|
paragraphs: vec![
|
||||||
Paragraph::new(UiDisplay::display_matching_info(
|
Paragraph::new(UiDisplay::display_matching_info(public.matches.as_ref())),
|
||||||
public.matches.as_ref().map(|m| m.matching),
|
|
||||||
)),
|
|
||||||
Paragraph::new("q: abort"),
|
Paragraph::new("q: abort"),
|
||||||
],
|
],
|
||||||
columns: 2,
|
columns: 2,
|
||||||
|
@ -22,7 +22,7 @@ use crate::tui::{
|
|||||||
display::UiDisplay,
|
display::UiDisplay,
|
||||||
error::ErrorOverlay,
|
error::ErrorOverlay,
|
||||||
info::{AlbumOverlay, ArtistOverlay},
|
info::{AlbumOverlay, ArtistOverlay},
|
||||||
matches::AlbumMatchesState,
|
matches::MatchesState,
|
||||||
minibuffer::Minibuffer,
|
minibuffer::Minibuffer,
|
||||||
overlay::{OverlayBuilder, OverlaySize},
|
overlay::{OverlayBuilder, OverlaySize},
|
||||||
reload::ReloadOverlay,
|
reload::ReloadOverlay,
|
||||||
@ -30,7 +30,7 @@ use crate::tui::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::app::AppPublicAlbumMatches;
|
use super::app::AppPublicMatchesKind;
|
||||||
|
|
||||||
pub trait IUi {
|
pub trait IUi {
|
||||||
fn render<APP: IAppAccess>(app: &mut APP, frame: &mut Frame);
|
fn render<APP: IAppAccess>(app: &mut APP, frame: &mut Frame);
|
||||||
@ -134,18 +134,28 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_matches_overlay(
|
fn render_matches_overlay(
|
||||||
matches: Option<AppPublicAlbumMatches>,
|
matches: Option<AppPublicMatchesKind>,
|
||||||
state: &mut WidgetState,
|
state: &mut WidgetState,
|
||||||
frame: &mut Frame,
|
frame: &mut Frame,
|
||||||
) {
|
) {
|
||||||
let area = OverlayBuilder::default().build(frame.size());
|
let area = OverlayBuilder::default().build(frame.size());
|
||||||
let (matching, list) = match matches {
|
let (matching, st) = match matches {
|
||||||
Some(m) => (Some(m.matching), Some(m.list)),
|
Some(kind) => match kind {
|
||||||
None => (None, None),
|
AppPublicMatchesKind::Artist(m) => (
|
||||||
|
UiDisplay::display_artist_matching_info(m.matching),
|
||||||
|
MatchesState::artists(m.list, state),
|
||||||
|
),
|
||||||
|
AppPublicMatchesKind::Album(m) => (
|
||||||
|
UiDisplay::display_album_matching_info(m.matching),
|
||||||
|
MatchesState::albums(m.list, state),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
None => (
|
||||||
|
UiDisplay::display_matching_nothing_info().to_string(),
|
||||||
|
MatchesState::empty(state),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
let matching_string = UiDisplay::display_matching_info(matching);
|
UiWidget::render_overlay_list_widget(&matching, st.list, st.state, true, area, frame)
|
||||||
let st = AlbumMatchesState::new(list.unwrap_or_default(), state);
|
|
||||||
UiWidget::render_overlay_list_widget(&matching_string, st.list, st.state, true, area, frame)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_error_overlay<S: AsRef<str>>(title: S, msg: S, frame: &mut Frame) {
|
fn render_error_overlay<S: AsRef<str>>(title: S, msg: S, frame: &mut Frame) {
|
||||||
@ -189,7 +199,10 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{AppPublic, AppPublicAlbumMatches, AppPublicInner, AppPublicMatches, Delta},
|
app::{
|
||||||
|
AppPublic, AppPublicAlbumMatches, AppPublicArtistMatches, AppPublicInner,
|
||||||
|
AppPublicMatches, Delta,
|
||||||
|
},
|
||||||
lib::interface::musicbrainz::Match,
|
lib::interface::musicbrainz::Match,
|
||||||
testmod::COLLECTION,
|
testmod::COLLECTION,
|
||||||
tests::terminal,
|
tests::terminal,
|
||||||
@ -211,9 +224,19 @@ mod tests {
|
|||||||
AppState::Reload(()) => AppState::Reload(()),
|
AppState::Reload(()) => AppState::Reload(()),
|
||||||
AppState::Search(s) => AppState::Search(s),
|
AppState::Search(s) => AppState::Search(s),
|
||||||
AppState::Matches(ref mut m) => AppState::Matches(AppPublicMatches {
|
AppState::Matches(ref mut m) => AppState::Matches(AppPublicMatches {
|
||||||
matches: m.matches.as_ref().map(|matches| AppPublicAlbumMatches {
|
matches: m.matches.as_ref().map(|k| match k {
|
||||||
matching: matches.matching,
|
AppPublicMatchesKind::Artist(a) => {
|
||||||
list: matches.list,
|
AppPublicMatchesKind::Artist(AppPublicArtistMatches {
|
||||||
|
matching: a.matching,
|
||||||
|
list: a.list,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
AppPublicMatchesKind::Album(a) => {
|
||||||
|
AppPublicMatchesKind::Album(AppPublicAlbumMatches {
|
||||||
|
matching: a.matching,
|
||||||
|
list: a.list,
|
||||||
|
})
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
state: m.state,
|
state: m.state,
|
||||||
}),
|
}),
|
||||||
@ -263,10 +286,10 @@ mod tests {
|
|||||||
widget_state.list.select(Some(0));
|
widget_state.list.select(Some(0));
|
||||||
|
|
||||||
app.state = AppState::Matches(AppPublicMatches {
|
app.state = AppState::Matches(AppPublicMatches {
|
||||||
matches: Some(AppPublicAlbumMatches {
|
matches: Some(AppPublicMatchesKind::Album(AppPublicAlbumMatches {
|
||||||
matching: &album,
|
matching: &album,
|
||||||
list: &album_matches,
|
list: &album_matches,
|
||||||
}),
|
})),
|
||||||
state: &mut widget_state,
|
state: &mut widget_state,
|
||||||
});
|
});
|
||||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user