diff --git a/src/application/handlers.rs b/src/application/handlers.rs index 43ade05..c157e17 100644 --- a/src/application/handlers.rs +++ b/src/application/handlers.rs @@ -111,7 +111,7 @@ impl App { match self.tab { Tab::Library => { - self.handle_library_click(x, rel_y); + self.handle_library_click(x, y); } Tab::Wanted => { self.select_list_item(&mut self.wanted_state.clone(), self.wanted.len(), rel_y); @@ -133,42 +133,39 @@ impl App { } } - fn handle_library_click(&mut self, x: u16, rel_y: usize) { - const ARTISTS_PANE_WIDTH: u16 = 32; - const BORDER_TOP: usize = 1; - const HEADER_HEIGHT: usize = 6; - const DIVIDER_HEIGHT: usize = 1; - const ALBUMS_START_ROW: usize = BORDER_TOP + HEADER_HEIGHT + DIVIDER_HEIGHT; + fn handle_library_click(&mut self, x: u16, y: u16) { + let artists = self.library.artists_inner_area; + let albums = self.library.albums_inner_area; + let tracks = self.library.tracks_inner_area; - if x < ARTISTS_PANE_WIDTH { - if rel_y > 0 && rel_y <= self.library.artists.len() { - self.library.artist_state.select(Some(rel_y - 1)); + if x >= artists.x && x < artists.x + artists.width + && y >= artists.y && y < artists.y + artists.height + { + let row = (y - artists.y) as usize; + if row < self.library.artists.len() { + self.library.artist_state.select(Some(row)); self.library.album_state.select(Some(0)); self.library.track_state.select(Some(0)); self.library.focus = LibraryFocus::Artists; } - } else if rel_y >= ALBUMS_START_ROW { - let album_row = rel_y - ALBUMS_START_ROW; - let content_height = self.main_area.height.saturating_sub(10) as usize; - let albums_section_height = (content_height * 40) / 100; - let tracks_start_row = ALBUMS_START_ROW + albums_section_height + DIVIDER_HEIGHT; - - if rel_y < tracks_start_row { - if let Some(artist) = self.library.selected_artist() - && album_row < artist.albums.len() - { - self.library.album_state.select(Some(album_row)); - self.library.track_state.select(Some(0)); - self.library.focus = LibraryFocus::Albums; - } - } else { - let track_row = rel_y - tracks_start_row; - if let Some(album) = self.library.selected_album() - && track_row < album.total as usize - { - self.library.track_state.select(Some(track_row)); - self.library.focus = LibraryFocus::Tracks; - } + } else if x >= albums.x && x < albums.x + albums.width + && y >= albums.y && y < albums.y + albums.height + { + let row = (y - albums.y) as usize; + if let Some(artist) = self.library.selected_artist() + && row < artist.albums.len() + { + self.library.album_state.select(Some(row)); + self.library.track_state.select(Some(0)); + self.library.focus = LibraryFocus::Albums; + } + } else if x >= tracks.x && x < tracks.x + tracks.width + && y >= tracks.y && y < tracks.y + tracks.height + { + let row = (y - tracks.y) as usize; + if row < self.library.tracks.len() { + self.library.track_state.select(Some(row)); + self.library.focus = LibraryFocus::Tracks; } } } diff --git a/src/application/library_state.rs b/src/application/library_state.rs index 3737973..84bacd7 100644 --- a/src/application/library_state.rs +++ b/src/application/library_state.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; +use ratatui::layout::Rect; use ratatui::widgets::ListState; use crate::data::{Album, Artist, Track}; @@ -21,6 +22,9 @@ pub struct LibraryState { pub artist_state: ListState, pub album_state: ListState, pub track_state: ListState, + pub(crate) artists_inner_area: Rect, + pub(crate) albums_inner_area: Rect, + pub(crate) tracks_inner_area: Rect, tracks_cache: HashMap>, pending_album_id: Option, } @@ -46,6 +50,9 @@ impl LibraryState { artist_state, album_state, track_state, + artists_inner_area: Rect::default(), + albums_inner_area: Rect::default(), + tracks_inner_area: Rect::default(), tracks_cache: HashMap::new(), pending_album_id: None, } diff --git a/src/presentation/library.rs b/src/presentation/library.rs index 69d2eb6..6b74461 100644 --- a/src/presentation/library.rs +++ b/src/presentation/library.rs @@ -12,7 +12,7 @@ use crate::application::library_state::{LibraryFocus, LibraryState}; use crate::data::{Album, AlbumStatus, Artist, MonitorState}; use crate::domain::aggregates::artist_status; use crate::theme; -use crate::ui::pane::{Pane, section_divider}; +use crate::ui::pane::Pane; use crate::ui::progress_bar::progress_bar; fn status_icon(status: AlbumStatus, monitored: bool) -> (char, Style) { @@ -64,7 +64,7 @@ pub fn render_library(frame: &mut Frame, area: Rect, state: &mut LibraryState) { render_detail_pane(frame, chunks[1], state); } -fn render_artists_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) { +pub fn render_artists_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) { let focused = state.focus == LibraryFocus::Artists; let artist_count = state.artists.len(); @@ -89,6 +89,7 @@ fn render_artists_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) let block = pane.build_block(); let inner = block.inner(area); frame.render_widget(block, area); + state.artists_inner_area = inner; let items: Vec = state .artists @@ -131,70 +132,40 @@ fn render_artists_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) frame.render_stateful_widget(list, inner, &mut state.artist_state); } -fn render_detail_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) { - let focused = state.focus == LibraryFocus::Albums || state.focus == LibraryFocus::Tracks; +pub fn render_detail_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) { + frame.render_widget( + Paragraph::new("").style(Style::default().bg(theme::BG0)), + area, + ); - let artist = state.selected_artist(); - - let meta = artist - .map(|a| { - format!( - "{} · {}", - a.country, - a.genres.first().map(|s| s.as_str()).unwrap_or("") - ) - }) - .unwrap_or_default(); - - let have_tracks: u16 = artist - .map(|a| a.albums.iter().map(|al| al.have).sum()) - .unwrap_or(0); - let total_tracks: u16 = artist - .map(|a| a.albums.iter().map(|al| al.total).sum()) - .unwrap_or(0); - - let footer = if artist.is_some() { - Line::from(vec![Span::styled( - format!("{}/{} tracks", have_tracks, total_tracks), - Style::default().fg(theme::GRAY), - )]) - } else { - Line::from("") - }; - - let pane = Pane::new("Detail") - .meta(&meta) - .focused(focused) - .footer(footer); - - let block = pane.build_block(); - let inner = block.inner(area); - frame.render_widget(block, area); - - let Some(artist) = artist else { + let Some(artist) = state.selected_artist() else { let msg = Paragraph::new(Span::styled( "No artist selected", Style::default().fg(theme::GRAY), )); - frame.render_widget(msg, inner); + frame.render_widget(msg, area); return; }; let chunks = Layout::vertical([ Constraint::Length(6), - Constraint::Length(1), Constraint::Percentage(40), - Constraint::Length(1), Constraint::Fill(1), ]) - .split(inner); + .split(area); render_artist_header(frame, chunks[0], artist); let albums_count = artist.albums.len(); let albums_label = format!("{} releases", albums_count); - let album_divider = section_divider("albums", Some(&albums_label)); - frame.render_widget(Paragraph::new(album_divider), chunks[1]); + let albums_focused = state.focus == LibraryFocus::Albums; + let albums_pane = Pane::new("Albums") + .meta(&albums_label) + .focused(albums_focused); + let albums_block = albums_pane.build_block(); + let albums_inner = albums_block.inner(chunks[1]); + frame.render_widget(albums_block, chunks[1]); + state.albums_inner_area = albums_inner; let selected_artist_idx = state.artist_state.selected(); if let Some(idx) = selected_artist_idx @@ -202,7 +173,7 @@ fn render_detail_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) { { let albums = artist.albums.clone(); let focus = state.focus; - render_albums_list(frame, chunks[2], &albums, focus, &mut state.album_state); + render_albums_list(frame, albums_inner, &albums, focus, &mut state.album_state); } let album_title = state @@ -213,14 +184,24 @@ fn render_detail_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState) { .selected_album() .map(|a| format!("{}/{}", a.have, a.total)) .unwrap_or_default(); - let track_label = format!("tracks · {}", album_title); - let track_divider = section_divider(&track_label, Some(&track_counts)); - frame.render_widget(Paragraph::new(track_divider), chunks[3]); + let track_meta = if album_title.is_empty() { + String::new() + } else { + format!("{} · {}", album_title, track_counts) + }; + let tracks_focused = state.focus == LibraryFocus::Tracks; + let tracks_pane = Pane::new("Tracks") + .meta(&track_meta) + .focused(tracks_focused); + let tracks_block = tracks_pane.build_block(); + let tracks_inner = tracks_block.inner(chunks[2]); + frame.render_widget(tracks_block, chunks[2]); + state.tracks_inner_area = tracks_inner; - render_tracks_list(frame, chunks[4], state); + render_tracks_list(frame, tracks_inner, state); } -fn render_artist_header(frame: &mut Frame, area: Rect, artist: &Artist) { +pub fn render_artist_header(frame: &mut Frame, area: Rect, artist: &Artist) { let have: u16 = artist.albums.iter().map(|a| a.have).sum(); let total: u16 = artist.albums.iter().map(|a| a.total).sum(); @@ -287,7 +268,7 @@ fn render_artist_header(frame: &mut Frame, area: Rect, artist: &Artist) { frame.render_widget(paragraph, area); } -fn render_albums_list( +pub fn render_albums_list( frame: &mut Frame, area: Rect, albums: &[Album], @@ -348,7 +329,7 @@ fn render_albums_list( frame.render_stateful_widget(list, area, album_state); } -fn render_tracks_list(frame: &mut Frame, area: Rect, state: &mut LibraryState) { +pub fn render_tracks_list(frame: &mut Frame, area: Rect, state: &mut LibraryState) { let focused = state.focus == LibraryFocus::Tracks; if state.tracks.is_empty() { diff --git a/src/ui/library.rs b/src/ui/library.rs index b01adf9..b739fad 100644 --- a/src/ui/library.rs +++ b/src/ui/library.rs @@ -1,2 +1,5 @@ pub use crate::application::library_state::{LibraryFocus, LibraryState}; -pub use crate::presentation::library::render_library; +pub use crate::presentation::library::{ + render_albums_list, render_artist_header, render_artists_pane, render_detail_pane, + render_library, render_tracks_list, +}; diff --git a/tests/snapshots/ui_snapshots__albums_list_snapshots__mixed_statuses.snap b/tests/snapshots/ui_snapshots__albums_list_snapshots__mixed_statuses.snap new file mode 100644 index 0000000..8dcf5e5 --- /dev/null +++ b/tests/snapshots/ui_snapshots__albums_list_snapshots__mixed_statuses.snap @@ -0,0 +1,14 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"● Complete Album [Album] 2020 ▰▰▰▰▰▰▰▰▰▰ 10/10 FLAC " +"○ Wanted Album [Album] 2021 ▱▱▱▱▱▱▱▱▱▱ 0/8 — " +"◌ Unmonitored Single [Single] 2022 ▱▱▱▱▱▱▱▱▱▱ 0/1 — " +" " +" " +" " +" " +" " +" " +" " diff --git a/tests/snapshots/ui_snapshots__albums_list_snapshots__with_albums_focused.snap b/tests/snapshots/ui_snapshots__albums_list_snapshots__with_albums_focused.snap new file mode 100644 index 0000000..52b6eee --- /dev/null +++ b/tests/snapshots/ui_snapshots__albums_list_snapshots__with_albums_focused.snap @@ -0,0 +1,14 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"● OK Computer [Album] 1997 ▰▰▰▰▰▰▰▰▰▰ 12/12 FLAC " +"◐ Kid A [Album] 2000 ▰▰▰▰▰▱▱▱▱▱ 5/10 FLAC " +" " +" " +" " +" " +" " +" " +" " +" " diff --git a/tests/snapshots/ui_snapshots__albums_list_snapshots__with_albums_unfocused.snap b/tests/snapshots/ui_snapshots__albums_list_snapshots__with_albums_unfocused.snap new file mode 100644 index 0000000..52b6eee --- /dev/null +++ b/tests/snapshots/ui_snapshots__albums_list_snapshots__with_albums_unfocused.snap @@ -0,0 +1,14 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"● OK Computer [Album] 1997 ▰▰▰▰▰▰▰▰▰▰ 12/12 FLAC " +"◐ Kid A [Album] 2000 ▰▰▰▰▰▱▱▱▱▱ 5/10 FLAC " +" " +" " +" " +" " +" " +" " +" " +" " diff --git a/tests/snapshots/ui_snapshots__artist_header_snapshots__monitored_artist.snap b/tests/snapshots/ui_snapshots__artist_header_snapshots__monitored_artist.snap new file mode 100644 index 0000000..2cc9007 --- /dev/null +++ b/tests/snapshots/ui_snapshots__artist_header_snapshots__monitored_artist.snap @@ -0,0 +1,10 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"Radiohead " +" " +"status ● Monitored path /music/Radiohead " +"quality FLAC size 2.5 GB " +"albums 2 tracks 17 / 22 " +" " diff --git a/tests/snapshots/ui_snapshots__artist_header_snapshots__unmonitored_artist.snap b/tests/snapshots/ui_snapshots__artist_header_snapshots__unmonitored_artist.snap new file mode 100644 index 0000000..cbe4bad --- /dev/null +++ b/tests/snapshots/ui_snapshots__artist_header_snapshots__unmonitored_artist.snap @@ -0,0 +1,10 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"Tool " +" " +"status ◌ Unmonitored path /music/Tool " +"quality FLAC size 3.8 GB " +"albums 0 tracks 0 / 0 " +" " diff --git a/tests/snapshots/ui_snapshots__artists_pane_snapshots__empty.snap b/tests/snapshots/ui_snapshots__artists_pane_snapshots__empty.snap new file mode 100644 index 0000000..38be7e6 --- /dev/null +++ b/tests/snapshots/ui_snapshots__artists_pane_snapshots__empty.snap @@ -0,0 +1,24 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"┌─[ Artists · 0 ]──────────────┐" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"└──────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__artists_pane_snapshots__with_artists_focused.snap b/tests/snapshots/ui_snapshots__artists_pane_snapshots__with_artists_focused.snap new file mode 100644 index 0000000..2c93191 --- /dev/null +++ b/tests/snapshots/ui_snapshots__artists_pane_snapshots__with_artists_focused.snap @@ -0,0 +1,24 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"┌─[ Artists · 2 ]──────────────┐" +"│◐ Radiohead 17/22 │" +"│! Pink Floyd 0/10 │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"└──────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__artists_pane_snapshots__with_artists_unfocused.snap b/tests/snapshots/ui_snapshots__artists_pane_snapshots__with_artists_unfocused.snap new file mode 100644 index 0000000..2c93191 --- /dev/null +++ b/tests/snapshots/ui_snapshots__artists_pane_snapshots__with_artists_unfocused.snap @@ -0,0 +1,24 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"┌─[ Artists · 2 ]──────────────┐" +"│◐ Radiohead 17/22 │" +"│! Pink Floyd 0/10 │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"└──────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__detail_pane_snapshots__no_artist_selected.snap b/tests/snapshots/ui_snapshots__detail_pane_snapshots__no_artist_selected.snap new file mode 100644 index 0000000..2e77729 --- /dev/null +++ b/tests/snapshots/ui_snapshots__detail_pane_snapshots__no_artist_selected.snap @@ -0,0 +1,28 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"No artist selected " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " diff --git a/tests/snapshots/ui_snapshots__detail_pane_snapshots__with_artist_albums_focused.snap b/tests/snapshots/ui_snapshots__detail_pane_snapshots__with_artist_albums_focused.snap new file mode 100644 index 0000000..2d8985c --- /dev/null +++ b/tests/snapshots/ui_snapshots__detail_pane_snapshots__with_artist_albums_focused.snap @@ -0,0 +1,28 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"Radiohead " +" " +"status ● Monitored path /music/Radiohead " +"quality FLAC size 2.5 GB " +"albums 2 tracks 17 / 22 " +" " +"┌─[ Albums · 2 releases ]──────────────────────────────────────────┐" +"│● OK Computer [Album] 1997 ▰▰▰▰▰▰▰▰▰▰ 12/12 FLAC │" +"│◐ Kid A [Album] 2000 ▰▰▰▰▰▱▱▱▱▱ 5/10 FLAC │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"└──────────────────────────────────────────────────────────────────┘" +"┌─[ Tracks · OK Computer · 12/12 ]─────────────────────────────────┐" +"│(no album selected) │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"└──────────────────────────────────────────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__detail_pane_snapshots__with_artist_tracks_focused.snap b/tests/snapshots/ui_snapshots__detail_pane_snapshots__with_artist_tracks_focused.snap new file mode 100644 index 0000000..cc58cf8 --- /dev/null +++ b/tests/snapshots/ui_snapshots__detail_pane_snapshots__with_artist_tracks_focused.snap @@ -0,0 +1,28 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"Radiohead " +" " +"status ● Monitored path /music/Radiohead " +"quality FLAC size 2.5 GB " +"albums 2 tracks 17 / 22 " +" " +"┌─[ Albums · 2 releases ]──────────────────────────────────────────┐" +"│● OK Computer [Album] 1997 ▰▰▰▰▰▰▰▰▰▰ 12/12 FLAC │" +"│◐ Kid A [Album] 2000 ▰▰▰▰▰▱▱▱▱▱ 5/10 FLAC │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"│ │" +"└──────────────────────────────────────────────────────────────────┘" +"┌─[ Tracks · OK Computer · 12/12 ]─────────────────────────────────┐" +"│✓ 01 Airbag 4:44 FLAC │" +"│✓ 02 Paranoid Android 6:23 FLAC │" +"│✗ 03 Subterranean Homesick Alien 4:27 — │" +"│ │" +"│ │" +"│ │" +"└──────────────────────────────────────────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__library_page_snapshots__full_page_empty.snap b/tests/snapshots/ui_snapshots__library_page_snapshots__full_page_empty.snap new file mode 100644 index 0000000..621e0cc --- /dev/null +++ b/tests/snapshots/ui_snapshots__library_page_snapshots__full_page_empty.snap @@ -0,0 +1,34 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"┌─[ Artists · 0 ]──────────────┐No artist selected " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"│ │ " +"└──────────────────────────────┘ " diff --git a/tests/snapshots/ui_snapshots__library_snapshots__albums_focused.snap b/tests/snapshots/ui_snapshots__library_page_snapshots__full_page_with_data.snap similarity index 68% rename from tests/snapshots/ui_snapshots__library_snapshots__albums_focused.snap rename to tests/snapshots/ui_snapshots__library_page_snapshots__full_page_with_data.snap index 8540a06..2fda0f8 100644 --- a/tests/snapshots/ui_snapshots__library_snapshots__albums_focused.snap +++ b/tests/snapshots/ui_snapshots__library_page_snapshots__full_page_with_data.snap @@ -2,14 +2,13 @@ source: tests/ui_snapshots.rs expression: terminal.backend() --- -"┌─[ Artists · 2 ]──────────────┐┌─[ Detail · UK · Alternative ]────────────────────────────────────┐" -"│◐ Radiohead 17/22 ││Radiohead │" -"│! Pink Floyd 0/10 ││ │" -"│ ││status ● Monitored path /music/Radiohead │" -"│ ││quality FLAC size 2.5 GB │" -"│ ││albums 2 tracks 17 / 22 │" -"│ ││ │" -"│ ││─ albums ─ 2 releases │" +"┌─[ Artists · 2 ]──────────────┐Radiohead " +"│◐ Radiohead 17/22 │ " +"│! Pink Floyd 0/10 │status ● Monitored path /music/Radiohead " +"│ │quality FLAC size 2.5 GB " +"│ │albums 2 tracks 17 / 22 " +"│ │ " +"│ │┌─[ Albums · 2 releases ]──────────────────────────────────────────┐" "│ ││● OK Computer [Album] 1997 ▰▰▰▰▰▰▰▰▰▰ 12/12 FLAC │" "│ ││◐ Kid A [Album] 2000 ▰▰▰▰▰▱▱▱▱▱ 5/10 FLAC │" "│ ││ │" @@ -20,8 +19,8 @@ expression: terminal.backend() "│ ││ │" "│ ││ │" "│ ││ │" -"│ ││ │" -"│ ││─ tracks · OK Computer ─ 12/12 │" +"│ │└──────────────────────────────────────────────────────────────────┘" +"│ │┌─[ Tracks · OK Computer · 12/12 ]─────────────────────────────────┐" "│ ││(no album selected) │" "│ ││ │" "│ ││ │" @@ -31,4 +30,5 @@ expression: terminal.backend() "│ ││ │" "│ ││ │" "│ ││ │" +"│ ││ │" "└──────────────────────────────┘└──────────────────────────────────────────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__library_snapshots__empty.snap b/tests/snapshots/ui_snapshots__library_snapshots__empty.snap deleted file mode 100644 index 26eeb5b..0000000 --- a/tests/snapshots/ui_snapshots__library_snapshots__empty.snap +++ /dev/null @@ -1,34 +0,0 @@ ---- -source: tests/ui_snapshots.rs -expression: terminal.backend() ---- -"┌─[ Artists · 0 ]──────────────┐┌─[ Detail · ]────────────────────────────────────────────────────┐" -"│ ││No artist selected │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"└──────────────────────────────┘└──────────────────────────────────────────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__library_snapshots__with_artists.snap b/tests/snapshots/ui_snapshots__library_snapshots__with_artists.snap deleted file mode 100644 index 8540a06..0000000 --- a/tests/snapshots/ui_snapshots__library_snapshots__with_artists.snap +++ /dev/null @@ -1,34 +0,0 @@ ---- -source: tests/ui_snapshots.rs -expression: terminal.backend() ---- -"┌─[ Artists · 2 ]──────────────┐┌─[ Detail · UK · Alternative ]────────────────────────────────────┐" -"│◐ Radiohead 17/22 ││Radiohead │" -"│! Pink Floyd 0/10 ││ │" -"│ ││status ● Monitored path /music/Radiohead │" -"│ ││quality FLAC size 2.5 GB │" -"│ ││albums 2 tracks 17 / 22 │" -"│ ││ │" -"│ ││─ albums ─ 2 releases │" -"│ ││● OK Computer [Album] 1997 ▰▰▰▰▰▰▰▰▰▰ 12/12 FLAC │" -"│ ││◐ Kid A [Album] 2000 ▰▰▰▰▰▱▱▱▱▱ 5/10 FLAC │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││─ tracks · OK Computer ─ 12/12 │" -"│ ││(no album selected) │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"│ ││ │" -"└──────────────────────────────┘└──────────────────────────────────────────────────────────────────┘" diff --git a/tests/snapshots/ui_snapshots__tracks_list_snapshots__no_tracks.snap b/tests/snapshots/ui_snapshots__tracks_list_snapshots__no_tracks.snap new file mode 100644 index 0000000..078cce9 --- /dev/null +++ b/tests/snapshots/ui_snapshots__tracks_list_snapshots__no_tracks.snap @@ -0,0 +1,12 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"(no album selected) " +" " +" " +" " +" " +" " +" " +" " diff --git a/tests/snapshots/ui_snapshots__tracks_list_snapshots__with_tracks_focused.snap b/tests/snapshots/ui_snapshots__tracks_list_snapshots__with_tracks_focused.snap new file mode 100644 index 0000000..0dc7eeb --- /dev/null +++ b/tests/snapshots/ui_snapshots__tracks_list_snapshots__with_tracks_focused.snap @@ -0,0 +1,12 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"✓ 01 Airbag 4:44 FLAC " +"✓ 02 Paranoid Android 6:23 FLAC " +"✗ 03 Subterranean Homesick Alien 4:27 — " +" " +" " +" " +" " +" " diff --git a/tests/snapshots/ui_snapshots__tracks_list_snapshots__with_tracks_unfocused.snap b/tests/snapshots/ui_snapshots__tracks_list_snapshots__with_tracks_unfocused.snap new file mode 100644 index 0000000..0dc7eeb --- /dev/null +++ b/tests/snapshots/ui_snapshots__tracks_list_snapshots__with_tracks_unfocused.snap @@ -0,0 +1,12 @@ +--- +source: tests/ui_snapshots.rs +expression: terminal.backend() +--- +"✓ 01 Airbag 4:44 FLAC " +"✓ 02 Paranoid Android 6:23 FLAC " +"✗ 03 Subterranean Homesick Alien 4:27 — " +" " +" " +" " +" " +" " diff --git a/tests/ui_snapshots.rs b/tests/ui_snapshots.rs index f1dfd60..bb21999 100644 --- a/tests/ui_snapshots.rs +++ b/tests/ui_snapshots.rs @@ -1,7 +1,10 @@ -use ratatui::{Terminal, backend::TestBackend, widgets::Paragraph}; +use ratatui::{backend::TestBackend, widgets::Paragraph, Terminal}; use ui_agregator::app::Tab; -use ui_agregator::data::{Album, AlbumStatus, Artist, MonitorState}; -use ui_agregator::ui::library::{LibraryFocus, LibraryState, render_library}; +use ui_agregator::data::{Album, AlbumStatus, Artist, MonitorState, Track}; +use ui_agregator::ui::library::{ + LibraryFocus, LibraryState, render_albums_list, render_artist_header, render_artists_pane, + render_detail_pane, render_library, render_tracks_list, +}; use ui_agregator::ui::modals::render_help_modal; use ui_agregator::ui::progress_bar::progress_bar; use ui_agregator::ui::topbar::render_topbar; @@ -66,6 +69,38 @@ fn test_artists() -> Vec { ] } +fn test_tracks() -> Vec { + vec![ + Track { + id: "t1".to_string(), + number: 1, + disc: 1, + title: "Airbag".to_string(), + duration: "4:44".to_string(), + have: true, + quality: "FLAC".to_string(), + }, + Track { + id: "t2".to_string(), + number: 2, + disc: 1, + title: "Paranoid Android".to_string(), + duration: "6:23".to_string(), + have: true, + quality: "FLAC".to_string(), + }, + Track { + id: "t3".to_string(), + number: 3, + disc: 1, + title: "Subterranean Homesick Alien".to_string(), + duration: "4:27".to_string(), + have: false, + quality: "—".to_string(), + }, + ] +} + mod progress_bar_snapshots { use super::*; @@ -143,47 +178,6 @@ mod topbar_snapshots { } } -mod library_snapshots { - use super::*; - - #[test] - fn empty() { - let mut terminal = Terminal::new(TestBackend::new(100, 30)).unwrap(); - let mut state = LibraryState::new(vec![]); - terminal - .draw(|f| { - render_library(f, f.area(), &mut state); - }) - .unwrap(); - insta::assert_snapshot!(terminal.backend()); - } - - #[test] - fn with_artists() { - let mut terminal = Terminal::new(TestBackend::new(100, 30)).unwrap(); - let mut state = LibraryState::new(test_artists()); - terminal - .draw(|f| { - render_library(f, f.area(), &mut state); - }) - .unwrap(); - insta::assert_snapshot!(terminal.backend()); - } - - #[test] - fn albums_focused() { - let mut terminal = Terminal::new(TestBackend::new(100, 30)).unwrap(); - let mut state = LibraryState::new(test_artists()); - state.focus = LibraryFocus::Albums; - terminal - .draw(|f| { - render_library(f, f.area(), &mut state); - }) - .unwrap(); - insta::assert_snapshot!(terminal.backend()); - } -} - mod help_modal_snapshots { use super::*; @@ -210,7 +204,277 @@ mod help_modal_snapshots { } } -mod library_state { +mod library_page_snapshots { + use super::*; + + #[test] + fn full_page_empty() { + let mut terminal = Terminal::new(TestBackend::new(100, 30)).unwrap(); + let mut state = LibraryState::new(vec![]); + terminal + .draw(|f| render_library(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn full_page_with_data() { + let mut terminal = Terminal::new(TestBackend::new(100, 30)).unwrap(); + let mut state = LibraryState::new(test_artists()); + terminal + .draw(|f| render_library(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } +} + +mod artists_pane_snapshots { + use super::*; + + #[test] + fn empty() { + let mut terminal = Terminal::new(TestBackend::new(32, 20)).unwrap(); + let mut state = LibraryState::new(vec![]); + terminal + .draw(|f| render_artists_pane(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn with_artists_focused() { + let mut terminal = Terminal::new(TestBackend::new(32, 20)).unwrap(); + let mut state = LibraryState::new(test_artists()); + state.focus = LibraryFocus::Artists; + terminal + .draw(|f| render_artists_pane(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn with_artists_unfocused() { + let mut terminal = Terminal::new(TestBackend::new(32, 20)).unwrap(); + let mut state = LibraryState::new(test_artists()); + state.focus = LibraryFocus::Albums; + terminal + .draw(|f| render_artists_pane(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } +} + +mod artist_header_snapshots { + use super::*; + + #[test] + fn monitored_artist() { + let mut terminal = Terminal::new(TestBackend::new(68, 6)).unwrap(); + let artists = test_artists(); + terminal + .draw(|f| render_artist_header(f, f.area(), &artists[0])) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn unmonitored_artist() { + let mut terminal = Terminal::new(TestBackend::new(68, 6)).unwrap(); + let artist = Artist { + id: "3".to_string(), + name: "Tool".to_string(), + country: "US".to_string(), + genres: vec!["Progressive Metal".to_string()], + monitor_state: MonitorState::Unmonitored, + path: "/music/Tool".to_string(), + quality: "FLAC".to_string(), + size_gb: 3.8, + albums: vec![], + }; + terminal + .draw(|f| render_artist_header(f, f.area(), &artist)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } +} + +mod albums_list_snapshots { + use super::*; + use ratatui::widgets::ListState; + + #[test] + fn with_albums_focused() { + let mut terminal = Terminal::new(TestBackend::new(68, 10)).unwrap(); + let artists = test_artists(); + let albums = &artists[0].albums; + let mut album_state = ListState::default(); + album_state.select(Some(0)); + terminal + .draw(|f| { + render_albums_list( + f, + f.area(), + albums, + LibraryFocus::Albums, + &mut album_state, + ); + }) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn with_albums_unfocused() { + let mut terminal = Terminal::new(TestBackend::new(68, 10)).unwrap(); + let artists = test_artists(); + let albums = &artists[0].albums; + let mut album_state = ListState::default(); + album_state.select(Some(0)); + terminal + .draw(|f| { + render_albums_list( + f, + f.area(), + albums, + LibraryFocus::Artists, + &mut album_state, + ); + }) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn mixed_statuses() { + let mut terminal = Terminal::new(TestBackend::new(68, 10)).unwrap(); + let albums = vec![ + Album { + id: "1".to_string(), + title: "Complete Album".to_string(), + year: 2020, + album_type: "Album".to_string(), + monitored: true, + total: 10, + have: 10, + quality: "FLAC".to_string(), + status: AlbumStatus::Complete, + }, + Album { + id: "2".to_string(), + title: "Wanted Album".to_string(), + year: 2021, + album_type: "Album".to_string(), + monitored: true, + total: 8, + have: 0, + quality: "—".to_string(), + status: AlbumStatus::Wanted, + }, + Album { + id: "3".to_string(), + title: "Unmonitored Single".to_string(), + year: 2022, + album_type: "Single".to_string(), + monitored: false, + total: 1, + have: 0, + quality: "—".to_string(), + status: AlbumStatus::Unmonitored, + }, + ]; + let mut album_state = ListState::default(); + album_state.select(Some(1)); + terminal + .draw(|f| { + render_albums_list( + f, + f.area(), + &albums, + LibraryFocus::Albums, + &mut album_state, + ); + }) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } +} + +mod tracks_list_snapshots { + use super::*; + + #[test] + fn no_tracks() { + let mut terminal = Terminal::new(TestBackend::new(68, 8)).unwrap(); + let mut state = LibraryState::new(test_artists()); + terminal + .draw(|f| render_tracks_list(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn with_tracks_focused() { + let mut terminal = Terminal::new(TestBackend::new(68, 8)).unwrap(); + let mut state = LibraryState::new(test_artists()); + state.tracks = test_tracks(); + state.focus = LibraryFocus::Tracks; + terminal + .draw(|f| render_tracks_list(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn with_tracks_unfocused() { + let mut terminal = Terminal::new(TestBackend::new(68, 8)).unwrap(); + let mut state = LibraryState::new(test_artists()); + state.tracks = test_tracks(); + state.focus = LibraryFocus::Artists; + terminal + .draw(|f| render_tracks_list(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } +} + +mod detail_pane_snapshots { + use super::*; + + #[test] + fn no_artist_selected() { + let mut terminal = Terminal::new(TestBackend::new(68, 24)).unwrap(); + let mut state = LibraryState::new(vec![]); + terminal + .draw(|f| render_detail_pane(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn with_artist_albums_focused() { + let mut terminal = Terminal::new(TestBackend::new(68, 24)).unwrap(); + let mut state = LibraryState::new(test_artists()); + state.focus = LibraryFocus::Albums; + terminal + .draw(|f| render_detail_pane(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } + + #[test] + fn with_artist_tracks_focused() { + let mut terminal = Terminal::new(TestBackend::new(68, 24)).unwrap(); + let mut state = LibraryState::new(test_artists()); + state.tracks = test_tracks(); + state.focus = LibraryFocus::Tracks; + terminal + .draw(|f| render_detail_pane(f, f.area(), &mut state)) + .unwrap(); + insta::assert_snapshot!(terminal.backend()); + } +} + +mod library_state_tests { use super::*; #[test]