From 66913b8e7678e655b2ed536536d8f061c930b02c Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Thu, 7 Mar 2024 22:19:14 +0100 Subject: [PATCH] Working status --- src/core/collection/album.rs | 65 +++++++++++---------- src/core/collection/track.rs | 10 +++- src/tui/ui.rs | 108 +++++++++++++++++++++++++++++++---- 3 files changed, 140 insertions(+), 43 deletions(-) diff --git a/src/core/collection/album.rs b/src/core/collection/album.rs index 9de9d3b..e56367f 100644 --- a/src/core/collection/album.rs +++ b/src/core/collection/album.rs @@ -8,6 +8,8 @@ use crate::core::collection::{ track::Track, }; +use super::track::TrackFormat; + /// An album is a collection of tracks that were released together. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Album { @@ -40,22 +42,16 @@ pub struct AlbumDate { pub day: u8, } -impl Display for AlbumDate { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.month.is_none() { - write!(f, "{}", self.year) - } else if self.day == 0 { - write!(f, "{}‐{:02}", self.year, self.month as u8) - } else { - write!(f, "{}‐{:02}‐{:02}", self.year, self.month as u8, self.day) +impl AlbumDate { + pub fn new>(year: u32, month: M, day: u8) -> Self { + AlbumDate { + year, + month: month.into(), + day, } } } -/// The album's sequence to determine order when two or more albums have the same release date. -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Ord, Eq, Hash)] -pub struct AlbumSeq(pub u8); - #[repr(u8)] #[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Ord, Eq, Hash)] pub enum AlbumMonth { @@ -96,16 +92,41 @@ impl From for AlbumMonth { } impl AlbumMonth { - fn is_none(&self) -> bool { + pub fn is_none(&self) -> bool { matches!(self, AlbumMonth::None) } } +/// The album's sequence to determine order when two or more albums have the same release date. +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Ord, Eq, Hash)] +pub struct AlbumSeq(pub u8); + +/// The album's ownership status. +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Ord, Eq, Hash)] +pub enum AlbumStatus { + #[default] + None, + Owned(TrackFormat), +} + +impl AlbumStatus { + pub fn from_tracks(tracks: &[Track]) -> AlbumStatus { + match tracks.iter().map(|t| t.quality.format).min() { + Some(format) => AlbumStatus::Owned(format), + None => AlbumStatus::None, + } + } +} + impl Album { pub fn get_sort_key(&self) -> (&AlbumDate, &AlbumSeq, &AlbumId) { (&self.date, &self.seq, &self.id) } + pub fn get_status(&self) -> AlbumStatus { + AlbumStatus::from_tracks(&self.tracks) + } + pub fn set_seq(&mut self, seq: AlbumSeq) { self.seq = seq; } @@ -166,16 +187,6 @@ mod tests { use super::*; - impl AlbumDate { - fn new>(year: u32, month: M, day: u8) -> Self { - AlbumDate { - year, - month: month.into(), - day, - } - } - } - #[test] fn album_month() { assert_eq!(>::into(0), AlbumMonth::None); @@ -195,14 +206,6 @@ mod tests { assert_eq!(>::into(255), AlbumMonth::None); } - #[test] - fn album_display() { - assert_eq!(AlbumDate::default().to_string(), "0"); - assert_eq!(AlbumDate::new(1990, 0, 0).to_string(), "1990"); - assert_eq!(AlbumDate::new(1990, 5, 0).to_string(), "1990‐05"); - assert_eq!(AlbumDate::new(1990, 5, 6).to_string(), "1990‐05‐06"); - } - #[test] fn same_date_seq_cmp() { let date = AlbumDate::new(2024, 3, 2); diff --git a/src/core/collection/track.rs b/src/core/collection/track.rs index dc4bc4f..4287669 100644 --- a/src/core/collection/track.rs +++ b/src/core/collection/track.rs @@ -33,10 +33,10 @@ impl Track { } /// The track file format. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum TrackFormat { - Flac, Mp3, + Flac, } impl PartialOrd for Track { @@ -61,6 +61,12 @@ impl Merge for Track { mod tests { use super::*; + #[test] + fn track_ord() { + assert!(TrackFormat::Mp3 < TrackFormat::Flac); + assert!(TrackFormat::Flac > TrackFormat::Mp3); + } + #[test] fn merge_track() { let left = Track { diff --git a/src/tui/ui.rs b/src/tui/ui.rs index 2d71e98..7caafd2 100644 --- a/src/tui/ui.rs +++ b/src/tui/ui.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; use musichoard::collection::{ - album::Album, + album::{Album, AlbumDate, AlbumSeq, AlbumStatus}, artist::Artist, - track::{Track, TrackFormat}, + track::{Track, TrackFormat, TrackQuality}, Collection, }; use ratatui::{ @@ -287,13 +287,19 @@ impl<'a, 'b> AlbumState<'a, 'b> { let album = state.list.selected().map(|i| &albums[i]); let info = Paragraph::new(format!( "Title: {}\n\ - Date: {}{}", + Date: {}{}\n\ + Status: {}", album.map(|a| a.id.title.as_str()).unwrap_or(""), - album.map(|a| a.date.to_string()).unwrap_or_default(), + album + .map(|a| Self::display_album_date(&a.date)) + .unwrap_or_default(), album .filter(|a| a.seq.0 > 0) - .map(|a| format!(" ({})", a.seq.0)) - .unwrap_or_default() + .map(|a| Self::display_album_seq(&a.seq)) + .unwrap_or_default(), + album + .map(|a| Self::display_album_status(&a.get_status())) + .unwrap_or("") )); AlbumState { @@ -303,6 +309,30 @@ impl<'a, 'b> AlbumState<'a, 'b> { info, } } + + fn display_album_date(date: &AlbumDate) -> String { + if date.month.is_none() { + format!("{}", date.year) + } else if date.day == 0 { + format!("{}‐{:02}", date.year, date.month as u8) + } else { + format!("{}‐{:02}‐{:02}", date.year, date.month as u8, date.day) + } + } + + fn display_album_seq(seq: &AlbumSeq) -> String { + format!(" ({})", seq.0) + } + + fn display_album_status(status: &AlbumStatus) -> &'static str { + match status { + AlbumStatus::None => "None", + AlbumStatus::Owned(format) => match format { + TrackFormat::Mp3 => "MP3", + TrackFormat::Flac => "FLAC", + }, + } + } } struct TrackState<'a, 'b> { @@ -331,10 +361,7 @@ impl<'a, 'b> TrackState<'a, 'b> { track.map(|t| t.id.title.as_str()).unwrap_or(""), track.map(|t| t.artist.join("; ")).unwrap_or_default(), track - .map(|t| match t.quality.format { - TrackFormat::Flac => "FLAC".to_string(), - TrackFormat::Mp3 => format!("MP3 {}kbps", t.quality.bitrate), - }) + .map(|t| Self::display_track_quality(&t.quality)) .unwrap_or_default(), )); @@ -345,6 +372,13 @@ impl<'a, 'b> TrackState<'a, 'b> { info, } } + + fn display_track_quality(quality: &TrackQuality) -> String { + match quality.format { + TrackFormat::Flac => "FLAC".to_string(), + TrackFormat::Mp3 => format!("MP3 {}kbps", quality.bitrate), + } + } } struct Minibuffer<'a> { @@ -743,6 +777,60 @@ mod tests { terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap(); } + #[test] + fn display_album_date() { + assert_eq!(AlbumState::display_album_date(&AlbumDate::default()), "0"); + assert_eq!( + AlbumState::display_album_date(&AlbumDate::new(1990, 0, 0)), + "1990" + ); + assert_eq!( + AlbumState::display_album_date(&AlbumDate::new(1990, 5, 0)), + "1990‐05" + ); + assert_eq!( + AlbumState::display_album_date(&AlbumDate::new(1990, 5, 6)), + "1990‐05‐06" + ); + } + + #[test] + fn display_album_seq() { + assert_eq!(AlbumState::display_album_seq(&AlbumSeq::default()), " (0)"); + assert_eq!(AlbumState::display_album_seq(&AlbumSeq(5)), " (5)"); + } + + #[test] + fn display_album_status() { + assert_eq!(AlbumState::display_album_status(&AlbumStatus::None), "None"); + assert_eq!( + AlbumState::display_album_status(&AlbumStatus::Owned(TrackFormat::Mp3)), + "MP3" + ); + assert_eq!( + AlbumState::display_album_status(&AlbumStatus::Owned(TrackFormat::Flac)), + "FLAC" + ); + } + + #[test] + fn display_track_quality() { + assert_eq!( + TrackState::display_track_quality(&TrackQuality { + format: TrackFormat::Flac, + bitrate: 1411 + }), + "FLAC" + ); + assert_eq!( + TrackState::display_track_quality(&TrackQuality { + format: TrackFormat::Mp3, + bitrate: 218 + }), + "MP3 218kbps" + ); + } + #[test] fn empty() { let artists: Vec = vec![];