Add a "cannot-have-an-mbid" entry to possible matches #208
@ -3,9 +3,9 @@ use std::{sync::mpsc, thread, time};
|
|||||||
use musichoard::collection::musicbrainz::IMusicBrainzRef;
|
use musichoard::collection::musicbrainz::IMusicBrainzRef;
|
||||||
|
|
||||||
use crate::tui::app::{
|
use crate::tui::app::{
|
||||||
machine::{matches::AppMatchesInfo, App, AppInner, AppMachine},
|
machine::{App, AppInner, AppMachine},
|
||||||
selection::{Delta, ListSelection},
|
selection::{Delta, ListSelection},
|
||||||
AppPublic, AppState, IAppInteractBrowse,
|
AppMatchesInfo, AppPublic, AppState, IAppInteractBrowse,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct AppBrowse;
|
pub struct AppBrowse;
|
||||||
@ -139,8 +139,8 @@ mod tests {
|
|||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{
|
app::{
|
||||||
machine::tests::{inner, inner_with_mb, music_hoard},
|
machine::tests::{inner, inner_with_mb, music_hoard},
|
||||||
AppPublicAlbumMatches, AppPublicArtistMatches, AppPublicMatchesInfo, Category,
|
AppAlbumMatches, AppArtistMatches, AppMatchesInfo, Category, IAppAccess, IAppInteract,
|
||||||
IAppAccess, IAppInteract, IAppInteractMatches,
|
IAppInteractMatches, MatchOption,
|
||||||
},
|
},
|
||||||
lib::interface::musicbrainz::{self, Match, MockIMusicBrainz},
|
lib::interface::musicbrainz::{self, Match, MockIMusicBrainz},
|
||||||
testmod::COLLECTION,
|
testmod::COLLECTION,
|
||||||
@ -263,11 +263,14 @@ mod tests {
|
|||||||
|
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
let expected = Some(AppPublicMatchesInfo::Album(AppPublicAlbumMatches {
|
let mut matches_1: Vec<MatchOption<Album>> =
|
||||||
matching: &album_1,
|
matches_1.into_iter().map(Into::into).collect();
|
||||||
list: &matches_1,
|
matches_1.push(MatchOption::CannotHaveMbid);
|
||||||
|
let expected = Some(AppMatchesInfo::Album(AppAlbumMatches {
|
||||||
|
matching: album_1.clone(),
|
||||||
|
list: matches_1.clone(),
|
||||||
}));
|
}));
|
||||||
assert_eq!(public_matches.matches, expected);
|
assert_eq!(public_matches.matches, expected.as_ref());
|
||||||
|
|
||||||
let mut app = app.unwrap_matches().select();
|
let mut app = app.unwrap_matches().select();
|
||||||
|
|
||||||
@ -276,11 +279,14 @@ mod tests {
|
|||||||
|
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
let expected = Some(AppPublicMatchesInfo::Album(AppPublicAlbumMatches {
|
let mut matches_4: Vec<MatchOption<Album>> =
|
||||||
matching: &album_4,
|
matches_4.into_iter().map(Into::into).collect();
|
||||||
list: &matches_4,
|
matches_4.push(MatchOption::CannotHaveMbid);
|
||||||
|
let expected = Some(AppMatchesInfo::Album(AppAlbumMatches {
|
||||||
|
matching: album_4.clone(),
|
||||||
|
list: matches_4.clone(),
|
||||||
}));
|
}));
|
||||||
assert_eq!(public_matches.matches, expected);
|
assert_eq!(public_matches.matches, expected.as_ref());
|
||||||
|
|
||||||
let app = app.unwrap_matches().select();
|
let app = app.unwrap_matches().select();
|
||||||
app.unwrap_browse();
|
app.unwrap_browse();
|
||||||
@ -324,11 +330,13 @@ mod tests {
|
|||||||
|
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
let expected = Some(AppPublicMatchesInfo::Artist(AppPublicArtistMatches {
|
let mut matches: Vec<MatchOption<Artist>> = matches.into_iter().map(Into::into).collect();
|
||||||
matching: &artist,
|
matches.push(MatchOption::CannotHaveMbid);
|
||||||
list: &matches,
|
let expected = Some(AppMatchesInfo::Artist(AppArtistMatches {
|
||||||
|
matching: artist.clone(),
|
||||||
|
list: matches.clone(),
|
||||||
}));
|
}));
|
||||||
assert_eq!(public_matches.matches, expected);
|
assert_eq!(public_matches.matches, expected.as_ref());
|
||||||
|
|
||||||
let app = app.unwrap_matches().select();
|
let app = app.unwrap_matches().select();
|
||||||
app.unwrap_browse();
|
app.unwrap_browse();
|
||||||
|
@ -1,80 +1,32 @@
|
|||||||
use std::{cmp, sync::mpsc};
|
use std::{cmp, sync::mpsc};
|
||||||
|
|
||||||
use musichoard::collection::{album::Album, artist::Artist};
|
use crate::tui::app::{
|
||||||
|
|
||||||
use crate::tui::{
|
|
||||||
app::{
|
|
||||||
machine::{App, AppInner, AppMachine},
|
machine::{App, AppInner, AppMachine},
|
||||||
AppPublic, AppPublicAlbumMatches, AppPublicArtistMatches, AppPublicMatches,
|
AppAlbumMatches, AppArtistMatches, AppMatchesInfo, AppPublic, AppPublicMatches, AppState,
|
||||||
AppPublicMatchesInfo, AppState, IAppInteractMatches, WidgetState,
|
IAppInteractMatches, MatchOption, WidgetState,
|
||||||
},
|
|
||||||
lib::interface::musicbrainz::Match,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
impl AppArtistMatches {
|
||||||
pub struct AppArtistMatchesInfo {
|
|
||||||
pub matching: Artist,
|
|
||||||
pub list: Vec<Match<Artist>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppArtistMatchesInfo {
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.list.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.list.len()
|
self.list.len()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'app> From<&'app AppArtistMatchesInfo> for AppPublicArtistMatches<'app> {
|
fn push_cannot_have_mbid(&mut self) {
|
||||||
fn from(value: &'app AppArtistMatchesInfo) -> Self {
|
self.list.push(MatchOption::CannotHaveMbid)
|
||||||
AppPublicArtistMatches {
|
|
||||||
matching: &value.matching,
|
|
||||||
list: &value.list,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
impl AppAlbumMatches {
|
||||||
pub struct AppAlbumMatchesInfo {
|
|
||||||
pub matching: Album,
|
|
||||||
pub list: Vec<Match<Album>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppAlbumMatchesInfo {
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.list.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.list.len()
|
self.list.len()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'app> From<&'app AppAlbumMatchesInfo> for AppPublicAlbumMatches<'app> {
|
fn push_cannot_have_mbid(&mut self) {
|
||||||
fn from(value: &'app AppAlbumMatchesInfo) -> Self {
|
self.list.push(MatchOption::CannotHaveMbid)
|
||||||
AppPublicAlbumMatches {
|
|
||||||
matching: &value.matching,
|
|
||||||
list: &value.list,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub enum AppMatchesInfo {
|
|
||||||
Artist(AppArtistMatchesInfo),
|
|
||||||
Album(AppAlbumMatchesInfo),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppMatchesInfo {
|
impl AppMatchesInfo {
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Artist(a) => a.is_empty(),
|
|
||||||
Self::Album(a) => a.is_empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Artist(a) => a.len(),
|
Self::Artist(a) => a.len(),
|
||||||
@ -82,20 +34,10 @@ impl AppMatchesInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn artist(matching: Artist, list: Vec<Match<Artist>>) -> Self {
|
fn push_cannot_have_mbid(&mut self) {
|
||||||
AppMatchesInfo::Artist(AppArtistMatchesInfo { matching, list })
|
match self {
|
||||||
}
|
Self::Artist(a) => a.push_cannot_have_mbid(),
|
||||||
|
Self::Album(a) => a.push_cannot_have_mbid(),
|
||||||
pub fn album(matching: Album, list: Vec<Match<Album>>) -> Self {
|
|
||||||
AppMatchesInfo::Album(AppAlbumMatchesInfo { matching, list })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'app> From<&'app AppMatchesInfo> for AppPublicMatchesInfo<'app> {
|
|
||||||
fn from(value: &'app AppMatchesInfo) -> Self {
|
|
||||||
match value {
|
|
||||||
AppMatchesInfo::Artist(a) => AppPublicMatchesInfo::Artist(a.into()),
|
|
||||||
AppMatchesInfo::Album(a) => AppPublicMatchesInfo::Album(a.into()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,13 +107,7 @@ impl IAppInteractMatches for AppMachine<AppMatches> {
|
|||||||
fn select(mut self) -> Self::APP {
|
fn select(mut self) -> Self::APP {
|
||||||
self.state.next_matches_info();
|
self.state.next_matches_info();
|
||||||
match self.state.current {
|
match self.state.current {
|
||||||
Some(ref matches_info) => {
|
Some(_) => self.into(),
|
||||||
self.state.state = WidgetState::default();
|
|
||||||
if !matches_info.is_empty() {
|
|
||||||
self.state.state.list.select(Some(0));
|
|
||||||
}
|
|
||||||
self.into()
|
|
||||||
}
|
|
||||||
None => AppMachine::browse(self.inner).into(),
|
None => AppMachine::browse(self.inner).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,11 +129,10 @@ impl IAppInteractMatchesPrivate for AppMatches {
|
|||||||
fn next_matches_info(&mut self) {
|
fn next_matches_info(&mut self) {
|
||||||
// FIXME: try_recv might not be appropriate for asynchronous version.
|
// FIXME: try_recv might not be appropriate for asynchronous version.
|
||||||
(self.current, self.state) = match self.matches_rx.try_recv() {
|
(self.current, self.state) = match self.matches_rx.try_recv() {
|
||||||
Ok(next_match) => {
|
Ok(mut next_match) => {
|
||||||
|
next_match.push_cannot_have_mbid();
|
||||||
let mut state = WidgetState::default();
|
let mut state = WidgetState::default();
|
||||||
if !next_match.is_empty() {
|
|
||||||
state.list.select(Some(0));
|
state.list.select(Some(0));
|
||||||
}
|
|
||||||
(Some(next_match), state)
|
(Some(next_match), state)
|
||||||
}
|
}
|
||||||
Err(_) => (None, WidgetState::default()),
|
Err(_) => (None, WidgetState::default()),
|
||||||
@ -209,13 +144,16 @@ impl IAppInteractMatchesPrivate for AppMatches {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use mpsc::Receiver;
|
use mpsc::Receiver;
|
||||||
use musichoard::collection::{
|
use musichoard::collection::{
|
||||||
album::{AlbumDate, AlbumId, AlbumPrimaryType, AlbumSecondaryType},
|
album::{Album, AlbumDate, AlbumId, AlbumPrimaryType, AlbumSecondaryType},
|
||||||
artist::ArtistId,
|
artist::{Artist, ArtistId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::tui::app::{
|
use crate::tui::{
|
||||||
|
app::{
|
||||||
machine::tests::{inner, music_hoard},
|
machine::tests::{inner, music_hoard},
|
||||||
IAppAccess,
|
IAppAccess,
|
||||||
|
},
|
||||||
|
lib::interface::musicbrainz::Match,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -287,6 +225,12 @@ mod tests {
|
|||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_cannot_have_mbid(matches_info_vec: &mut [AppMatchesInfo]) {
|
||||||
|
for matches_info in matches_info_vec.iter_mut() {
|
||||||
|
matches_info.push_cannot_have_mbid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_empty() {
|
fn create_empty() {
|
||||||
let matches = AppMachine::matches(inner(music_hoard(vec![])), receiver(vec![]));
|
let matches = AppMachine::matches(inner(music_hoard(vec![])), receiver(vec![]));
|
||||||
@ -306,11 +250,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_nonempty() {
|
fn create_nonempty() {
|
||||||
let matches_info_vec = album_matches_info_vec();
|
let mut matches_info_vec = album_matches_info_vec();
|
||||||
let matches = AppMachine::matches(
|
let matches = AppMachine::matches(
|
||||||
inner(music_hoard(vec![])),
|
inner(music_hoard(vec![])),
|
||||||
receiver(matches_info_vec.clone()),
|
receiver(matches_info_vec.clone()),
|
||||||
);
|
);
|
||||||
|
push_cannot_have_mbid(&mut matches_info_vec);
|
||||||
|
|
||||||
let mut widget_state = WidgetState::default();
|
let mut widget_state = WidgetState::default();
|
||||||
widget_state.list.select(Some(0));
|
widget_state.list.select(Some(0));
|
||||||
@ -322,15 +267,16 @@ mod tests {
|
|||||||
let public = app.get();
|
let public = app.get();
|
||||||
let public_matches = public.state.unwrap_matches();
|
let public_matches = public.state.unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(public_matches.matches, Some((&matches_info_vec[0]).into()));
|
assert_eq!(public_matches.matches, Some(&matches_info_vec[0]));
|
||||||
assert_eq!(public_matches.state, &widget_state);
|
assert_eq!(public_matches.state, &widget_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_flow(matches_info_vec: Vec<AppMatchesInfo>) {
|
fn matches_flow(mut matches_info_vec: Vec<AppMatchesInfo>) {
|
||||||
let matches = AppMachine::matches(
|
let matches = AppMachine::matches(
|
||||||
inner(music_hoard(vec![])),
|
inner(music_hoard(vec![])),
|
||||||
receiver(matches_info_vec.clone()),
|
receiver(matches_info_vec.clone()),
|
||||||
);
|
);
|
||||||
|
push_cannot_have_mbid(&mut matches_info_vec);
|
||||||
|
|
||||||
let mut widget_state = WidgetState::default();
|
let mut widget_state = WidgetState::default();
|
||||||
widget_state.list.select(Some(0));
|
widget_state.list.select(Some(0));
|
||||||
@ -348,10 +294,16 @@ mod tests {
|
|||||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info_vec[0]));
|
assert_eq!(matches.state.current.as_ref(), Some(&matches_info_vec[0]));
|
||||||
assert_eq!(matches.state.state.list.selected(), Some(1));
|
assert_eq!(matches.state.state.list.selected(), Some(1));
|
||||||
|
|
||||||
|
// Next is CannotHaveMBID
|
||||||
let matches = matches.next_match().unwrap_matches();
|
let matches = matches.next_match().unwrap_matches();
|
||||||
|
|
||||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info_vec[0]));
|
assert_eq!(matches.state.current.as_ref(), Some(&matches_info_vec[0]));
|
||||||
assert_eq!(matches.state.state.list.selected(), Some(1));
|
assert_eq!(matches.state.state.list.selected(), Some(2));
|
||||||
|
|
||||||
|
let matches = matches.next_match().unwrap_matches();
|
||||||
|
|
||||||
|
assert_eq!(matches.state.current.as_ref(), Some(&matches_info_vec[0]));
|
||||||
|
assert_eq!(matches.state.state.list.selected(), Some(2));
|
||||||
|
|
||||||
let matches = matches.select().unwrap_matches();
|
let matches = matches.select().unwrap_matches();
|
||||||
|
|
||||||
@ -374,11 +326,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn matches_abort() {
|
fn matches_abort() {
|
||||||
let matches_info_vec = album_matches_info_vec();
|
let mut matches_info_vec = album_matches_info_vec();
|
||||||
let matches = AppMachine::matches(
|
let matches = AppMachine::matches(
|
||||||
inner(music_hoard(vec![])),
|
inner(music_hoard(vec![])),
|
||||||
receiver(matches_info_vec.clone()),
|
receiver(matches_info_vec.clone()),
|
||||||
);
|
);
|
||||||
|
push_cannot_have_mbid(&mut matches_info_vec);
|
||||||
|
|
||||||
let mut widget_state = WidgetState::default();
|
let mut widget_state = WidgetState::default();
|
||||||
widget_state.list.select(Some(0));
|
widget_state.list.select(Some(0));
|
||||||
|
@ -129,26 +129,50 @@ pub struct AppPublicInner<'app> {
|
|||||||
pub selection: &'app mut Selection,
|
pub selection: &'app mut Selection,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct AppPublicArtistMatches<'app> {
|
pub enum MatchOption<T> {
|
||||||
pub matching: &'app Artist,
|
Match(Match<T>),
|
||||||
pub list: &'app [Match<Artist>],
|
CannotHaveMbid,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
impl<T> From<Match<T>> for MatchOption<T> {
|
||||||
pub struct AppPublicAlbumMatches<'app> {
|
fn from(value: Match<T>) -> Self {
|
||||||
pub matching: &'app Album,
|
MatchOption::Match(value)
|
||||||
pub list: &'app [Match<Album>],
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum AppPublicMatchesInfo<'app> {
|
pub struct AppArtistMatches {
|
||||||
Artist(AppPublicArtistMatches<'app>),
|
pub matching: Artist,
|
||||||
Album(AppPublicAlbumMatches<'app>),
|
pub list: Vec<MatchOption<Artist>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct AppAlbumMatches {
|
||||||
|
pub matching: Album,
|
||||||
|
pub list: Vec<MatchOption<Album>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum AppMatchesInfo {
|
||||||
|
Artist(AppArtistMatches),
|
||||||
|
Album(AppAlbumMatches),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppMatchesInfo {
|
||||||
|
pub fn artist<M: Into<MatchOption<Artist>>>(matching: Artist, list: Vec<M>) -> Self {
|
||||||
|
let list: Vec<MatchOption<Artist>> = list.into_iter().map(Into::into).collect();
|
||||||
|
AppMatchesInfo::Artist(AppArtistMatches { matching, list })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn album<M: Into<MatchOption<Album>>>(matching: Album, list: Vec<M>) -> Self {
|
||||||
|
let list: Vec<MatchOption<Album>> = list.into_iter().map(Into::into).collect();
|
||||||
|
AppMatchesInfo::Album(AppAlbumMatches { matching, list })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppPublicMatches<'app> {
|
pub struct AppPublicMatches<'app> {
|
||||||
pub matches: Option<AppPublicMatchesInfo<'app>>,
|
pub matches: Option<&'app AppMatchesInfo>,
|
||||||
pub state: &'app mut WidgetState,
|
pub state: &'app mut WidgetState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use musichoard::collection::{
|
|||||||
track::{TrackFormat, TrackQuality},
|
track::{TrackFormat, TrackQuality},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::tui::{app::AppPublicMatchesInfo, lib::interface::musicbrainz::Match};
|
use crate::tui::app::{AppMatchesInfo, MatchOption};
|
||||||
|
|
||||||
pub struct UiDisplay;
|
pub struct UiDisplay;
|
||||||
|
|
||||||
@ -114,18 +114,19 @@ impl UiDisplay {
|
|||||||
"Matching nothing"
|
"Matching nothing"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_matching_info(matches: Option<&AppPublicMatchesInfo>) -> String {
|
pub fn display_matching_info(matches: Option<&AppMatchesInfo>) -> String {
|
||||||
match matches.as_ref() {
|
match matches.as_ref() {
|
||||||
Some(kind) => match kind {
|
Some(kind) => match kind {
|
||||||
AppPublicMatchesInfo::Artist(m) => UiDisplay::display_artist_matching(m.matching),
|
AppMatchesInfo::Artist(m) => UiDisplay::display_artist_matching(&m.matching),
|
||||||
AppPublicMatchesInfo::Album(m) => UiDisplay::display_album_matching(m.matching),
|
AppMatchesInfo::Album(m) => UiDisplay::display_album_matching(&m.matching),
|
||||||
},
|
},
|
||||||
None => UiDisplay::display_nothing_matching().to_string(),
|
None => UiDisplay::display_nothing_matching().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_artist_match(match_artist: &Match<Artist>) -> String {
|
pub fn display_artist_match(match_option: &MatchOption<Artist>) -> String {
|
||||||
format!(
|
match match_option {
|
||||||
|
MatchOption::Match(match_artist) => format!(
|
||||||
"{}{} ({}%)",
|
"{}{} ({}%)",
|
||||||
&match_artist.item.id.name,
|
&match_artist.item.id.name,
|
||||||
&match_artist
|
&match_artist
|
||||||
@ -134,11 +135,14 @@ impl UiDisplay {
|
|||||||
.map(|d| format!(" ({d})"))
|
.map(|d| format!(" ({d})"))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
match_artist.score,
|
match_artist.score,
|
||||||
)
|
),
|
||||||
|
MatchOption::CannotHaveMbid => Self::display_cannot_have_mbid().to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_album_match(match_album: &Match<Album>) -> String {
|
pub fn display_album_match(match_option: &MatchOption<Album>) -> String {
|
||||||
format!(
|
match match_option {
|
||||||
|
MatchOption::Match(match_album) => format!(
|
||||||
"{:010} | {} [{}] ({}%)",
|
"{:010} | {} [{}] ({}%)",
|
||||||
UiDisplay::display_album_date(&match_album.item.date),
|
UiDisplay::display_album_date(&match_album.item.date),
|
||||||
&match_album.item.id.title,
|
&match_album.item.id.title,
|
||||||
@ -147,7 +151,13 @@ impl UiDisplay {
|
|||||||
&match_album.item.secondary_types
|
&match_album.item.secondary_types
|
||||||
),
|
),
|
||||||
match_album.score,
|
match_album.score,
|
||||||
)
|
),
|
||||||
|
MatchOption::CannotHaveMbid => Self::display_cannot_have_mbid().to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_cannot_have_mbid() -> &'static str {
|
||||||
|
"-- Cannot have a MusicBrainz Identifier --"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ use musichoard::collection::{album::Album, artist::Artist};
|
|||||||
use ratatui::widgets::{List, ListItem};
|
use ratatui::widgets::{List, ListItem};
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{AppPublicMatchesInfo, WidgetState},
|
app::{AppMatchesInfo, MatchOption, WidgetState},
|
||||||
lib::interface::musicbrainz::Match,
|
|
||||||
ui::display::UiDisplay,
|
ui::display::UiDisplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -14,11 +13,11 @@ pub struct MatchesState<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> MatchesState<'a, 'b> {
|
impl<'a, 'b> MatchesState<'a, 'b> {
|
||||||
pub fn new(matches: Option<AppPublicMatchesInfo>, state: &'b mut WidgetState) -> Self {
|
pub fn new(matches: Option<&AppMatchesInfo>, state: &'b mut WidgetState) -> Self {
|
||||||
match matches {
|
match matches {
|
||||||
Some(info) => match info {
|
Some(info) => match info {
|
||||||
AppPublicMatchesInfo::Artist(m) => Self::artists(m.matching, m.list, state),
|
AppMatchesInfo::Artist(m) => Self::artists(&m.matching, &m.list, state),
|
||||||
AppPublicMatchesInfo::Album(m) => Self::albums(m.matching, m.list, state),
|
AppMatchesInfo::Album(m) => Self::albums(&m.matching, &m.list, state),
|
||||||
},
|
},
|
||||||
None => Self::empty(state),
|
None => Self::empty(state),
|
||||||
}
|
}
|
||||||
@ -32,7 +31,11 @@ impl<'a, 'b> MatchesState<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn artists(matching: &Artist, matches: &[Match<Artist>], state: &'b mut WidgetState) -> Self {
|
fn artists(
|
||||||
|
matching: &Artist,
|
||||||
|
matches: &[MatchOption<Artist>],
|
||||||
|
state: &'b mut WidgetState,
|
||||||
|
) -> Self {
|
||||||
let matching = UiDisplay::display_artist_matching(matching);
|
let matching = UiDisplay::display_artist_matching(matching);
|
||||||
|
|
||||||
let list = List::new(
|
let list = List::new(
|
||||||
@ -50,7 +53,11 @@ impl<'a, 'b> MatchesState<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn albums(matching: &Album, matches: &[Match<Album>], state: &'b mut WidgetState) -> Self {
|
fn albums(
|
||||||
|
matching: &Album,
|
||||||
|
matches: &[MatchOption<Album>],
|
||||||
|
state: &'b mut WidgetState,
|
||||||
|
) -> Self {
|
||||||
let matching = UiDisplay::display_album_matching(matching);
|
let matching = UiDisplay::display_album_matching(matching);
|
||||||
|
|
||||||
let list = List::new(
|
let list = List::new(
|
||||||
|
@ -59,7 +59,7 @@ impl Minibuffer<'_> {
|
|||||||
},
|
},
|
||||||
AppState::Matches(public) => Minibuffer {
|
AppState::Matches(public) => Minibuffer {
|
||||||
paragraphs: vec![
|
paragraphs: vec![
|
||||||
Paragraph::new(UiDisplay::display_matching_info(public.matches.as_ref())),
|
Paragraph::new(UiDisplay::display_matching_info(public.matches)),
|
||||||
Paragraph::new("q: abort"),
|
Paragraph::new("q: abort"),
|
||||||
],
|
],
|
||||||
columns: 2,
|
columns: 2,
|
||||||
|
@ -14,10 +14,7 @@ use ratatui::{layout::Rect, widgets::Paragraph, Frame};
|
|||||||
use musichoard::collection::{album::Album, Collection};
|
use musichoard::collection::{album::Album, Collection};
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{
|
app::{AppMatchesInfo, AppPublicState, AppState, Category, IAppAccess, Selection, WidgetState},
|
||||||
AppPublicMatchesInfo, AppPublicState, AppState, Category, IAppAccess, Selection,
|
|
||||||
WidgetState,
|
|
||||||
},
|
|
||||||
ui::{
|
ui::{
|
||||||
browse::{
|
browse::{
|
||||||
AlbumArea, AlbumState, ArtistArea, ArtistState, FrameArea, TrackArea, TrackState,
|
AlbumArea, AlbumState, ArtistArea, ArtistState, FrameArea, TrackArea, TrackState,
|
||||||
@ -135,7 +132,7 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_matches_overlay(
|
fn render_matches_overlay(
|
||||||
matches: Option<AppPublicMatchesInfo>,
|
matches: Option<&AppMatchesInfo>,
|
||||||
state: &mut WidgetState,
|
state: &mut WidgetState,
|
||||||
frame: &mut Frame,
|
frame: &mut Frame,
|
||||||
) {
|
) {
|
||||||
@ -185,10 +182,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
app::{
|
app::{AppPublic, AppPublicInner, AppPublicMatches, Delta, MatchOption},
|
||||||
AppPublic, AppPublicAlbumMatches, AppPublicArtistMatches, AppPublicInner,
|
|
||||||
AppPublicMatches, Delta,
|
|
||||||
},
|
|
||||||
lib::interface::musicbrainz::Match,
|
lib::interface::musicbrainz::Match,
|
||||||
testmod::COLLECTION,
|
testmod::COLLECTION,
|
||||||
tests::terminal,
|
tests::terminal,
|
||||||
@ -196,33 +190,6 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<'app> AppPublicArtistMatches<'app> {
|
|
||||||
fn get(&self) -> AppPublicArtistMatches<'app> {
|
|
||||||
AppPublicArtistMatches {
|
|
||||||
matching: self.matching,
|
|
||||||
list: self.list,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'app> AppPublicAlbumMatches<'app> {
|
|
||||||
fn get(&self) -> AppPublicAlbumMatches<'app> {
|
|
||||||
AppPublicAlbumMatches {
|
|
||||||
matching: self.matching,
|
|
||||||
list: self.list,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'app> AppPublicMatchesInfo<'app> {
|
|
||||||
fn get(&self) -> AppPublicMatchesInfo<'app> {
|
|
||||||
match self {
|
|
||||||
Self::Artist(a) => Self::Artist(a.get()),
|
|
||||||
Self::Album(a) => Self::Album(a.get()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Automock does not support returning types with generic lifetimes.
|
// Automock does not support returning types with generic lifetimes.
|
||||||
impl<'app> IAppAccess for AppPublic<'app> {
|
impl<'app> IAppAccess for AppPublic<'app> {
|
||||||
fn get(&mut self) -> AppPublic {
|
fn get(&mut self) -> AppPublic {
|
||||||
@ -237,7 +204,7 @@ 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_mut().map(|k| k.get()),
|
matches: m.matches,
|
||||||
state: m.state,
|
state: m.state,
|
||||||
}),
|
}),
|
||||||
AppState::Error(s) => AppState::Error(s),
|
AppState::Error(s) => AppState::Error(s),
|
||||||
@ -257,18 +224,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn artist_matches<'app>(
|
fn artist_matches(matching: Artist, list: Vec<Match<Artist>>) -> AppMatchesInfo {
|
||||||
matching: &'app Artist,
|
let mut list: Vec<MatchOption<Artist>> = list.into_iter().map(Into::into).collect();
|
||||||
list: &'app [Match<Artist>],
|
list.push(MatchOption::CannotHaveMbid);
|
||||||
) -> AppPublicMatchesInfo<'app> {
|
AppMatchesInfo::artist(matching, list)
|
||||||
AppPublicMatchesInfo::Artist(AppPublicArtistMatches { matching, list })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn album_matches<'app>(
|
fn album_matches(matching: Album, list: Vec<Match<Album>>) -> AppMatchesInfo {
|
||||||
matching: &'app Album,
|
let mut list: Vec<MatchOption<Album>> = list.into_iter().map(Into::into).collect();
|
||||||
list: &'app [Match<Album>],
|
list.push(MatchOption::CannotHaveMbid);
|
||||||
) -> AppPublicMatchesInfo<'app> {
|
AppMatchesInfo::album(matching, list)
|
||||||
AppPublicMatchesInfo::Album(AppPublicAlbumMatches { matching, list })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_test_suite(collection: &Collection, selection: &mut Selection) {
|
fn draw_test_suite(collection: &Collection, selection: &mut Selection) {
|
||||||
@ -364,21 +329,21 @@ mod tests {
|
|||||||
let mut terminal = terminal();
|
let mut terminal = terminal();
|
||||||
|
|
||||||
let artist = Artist::new(ArtistId::new("an artist"));
|
let artist = Artist::new(ArtistId::new("an artist"));
|
||||||
|
|
||||||
let artist_match = Match {
|
let artist_match = Match {
|
||||||
score: 80,
|
score: 80,
|
||||||
item: artist.clone(),
|
item: artist.clone(),
|
||||||
disambiguation: None,
|
disambiguation: None,
|
||||||
};
|
};
|
||||||
|
let list = vec![artist_match.clone(), artist_match.clone()];
|
||||||
|
let artist_matches = artist_matches(artist, list);
|
||||||
|
|
||||||
let list = [artist_match.clone(), artist_match.clone()];
|
|
||||||
let mut widget_state = WidgetState::default();
|
let mut widget_state = WidgetState::default();
|
||||||
widget_state.list.select(Some(0));
|
widget_state.list.select(Some(0));
|
||||||
|
|
||||||
let mut app = AppPublic {
|
let mut app = AppPublic {
|
||||||
inner: public_inner(collection, &mut selection),
|
inner: public_inner(collection, &mut selection),
|
||||||
state: AppState::Matches(AppPublicMatches {
|
state: AppState::Matches(AppPublicMatches {
|
||||||
matches: Some(artist_matches(&artist, &list)),
|
matches: Some(&artist_matches),
|
||||||
state: &mut widget_state,
|
state: &mut widget_state,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@ -398,21 +363,21 @@ mod tests {
|
|||||||
Some(AlbumPrimaryType::Album),
|
Some(AlbumPrimaryType::Album),
|
||||||
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
||||||
);
|
);
|
||||||
|
|
||||||
let album_match = Match {
|
let album_match = Match {
|
||||||
score: 80,
|
score: 80,
|
||||||
item: album.clone(),
|
item: album.clone(),
|
||||||
disambiguation: None,
|
disambiguation: None,
|
||||||
};
|
};
|
||||||
|
let list = vec![album_match.clone(), album_match.clone()];
|
||||||
|
let album_matches = album_matches(album, list);
|
||||||
|
|
||||||
let list = [album_match.clone(), album_match.clone()];
|
|
||||||
let mut widget_state = WidgetState::default();
|
let mut widget_state = WidgetState::default();
|
||||||
widget_state.list.select(Some(0));
|
widget_state.list.select(Some(0));
|
||||||
|
|
||||||
let mut app = AppPublic {
|
let mut app = AppPublic {
|
||||||
inner: public_inner(collection, &mut selection),
|
inner: public_inner(collection, &mut selection),
|
||||||
state: AppState::Matches(AppPublicMatches {
|
state: AppState::Matches(AppPublicMatches {
|
||||||
matches: Some(album_matches(&album, &list)),
|
matches: Some(&album_matches),
|
||||||
state: &mut widget_state,
|
state: &mut widget_state,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user