feat: add gRPC client with config-based server address and album support
- Add tonic/prost gRPC client connecting to music-agregator service - Add config.yaml for configurable server host/port - Add build.rs for proto compilation from music-agregator - Update Artist/Album models to match proto with MonitorState enum - Convert album list from GetArtists response - Fix album click selection with correct layout offsets - Improve monitor state icons for better visibility
This commit is contained in:
+31
-11
@@ -8,7 +8,7 @@ use ratatui::{
|
||||
widgets::{List, ListItem, ListState, Paragraph},
|
||||
};
|
||||
|
||||
use crate::data::{Album, AlbumStatus, Artist, Track};
|
||||
use crate::data::{Album, AlbumStatus, Artist, MonitorState, Track};
|
||||
use crate::theme;
|
||||
use crate::ui::pane::{Pane, section_divider};
|
||||
use crate::ui::progress_bar::progress_bar;
|
||||
@@ -201,6 +201,20 @@ fn status_icon(status: AlbumStatus, monitored: bool) -> (char, Style) {
|
||||
}
|
||||
}
|
||||
|
||||
fn monitor_state_icon(state: MonitorState, status: AlbumStatus) -> (char, Style) {
|
||||
match state {
|
||||
MonitorState::Monitored => match status {
|
||||
AlbumStatus::Complete => ('✓', Style::default().fg(theme::GREEN)),
|
||||
AlbumStatus::Partial => ('◐', Style::default().fg(theme::YELLOW)),
|
||||
AlbumStatus::Wanted => ('!', Style::default().fg(theme::RED)),
|
||||
AlbumStatus::Unmonitored => ('-', Style::default().fg(theme::GRAY)),
|
||||
},
|
||||
MonitorState::Unmonitored => ('-', Style::default().fg(theme::GRAY)),
|
||||
MonitorState::Excluded => ('x', Style::default().fg(theme::RED)),
|
||||
MonitorState::Unspecified => ('?', Style::default().fg(theme::GRAY)),
|
||||
}
|
||||
}
|
||||
|
||||
fn track_icon(have: bool) -> (char, Style) {
|
||||
if have {
|
||||
('✓', Style::default().fg(theme::GREEN))
|
||||
@@ -267,15 +281,12 @@ fn render_artists_pane(frame: &mut Frame, area: Rect, state: &mut LibraryState)
|
||||
.iter()
|
||||
.map(|artist| {
|
||||
let status = artist_status(artist);
|
||||
let (icon_char, icon_style) = status_icon(status, artist.monitored);
|
||||
let (icon_char, icon_style) = monitor_state_icon(artist.monitor_state, status);
|
||||
|
||||
let total: u16 = artist.albums.iter().map(|a| a.total).sum();
|
||||
let have: u16 = artist.albums.iter().map(|a| a.have).sum();
|
||||
|
||||
let mut name_text = artist.name.clone();
|
||||
if !artist.monitored {
|
||||
name_text.push_str(" ·unm");
|
||||
}
|
||||
|
||||
let count_str = format!("{}/{}", have, total);
|
||||
let name_width = inner.width as usize - 2 - count_str.len() - 2;
|
||||
@@ -399,18 +410,27 @@ 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();
|
||||
|
||||
let (status_icon, status_text, status_style) = if artist.monitored {
|
||||
(
|
||||
let (status_icon, status_text, status_style) = match artist.monitor_state {
|
||||
MonitorState::Monitored => (
|
||||
Span::styled("● ", Style::default().fg(theme::GREEN)),
|
||||
"Monitored",
|
||||
Style::default().fg(theme::FG2),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
),
|
||||
MonitorState::Unmonitored => (
|
||||
Span::styled("◌ ", Style::default().fg(theme::GRAY)),
|
||||
"Unmonitored",
|
||||
Style::default().fg(theme::GRAY),
|
||||
)
|
||||
),
|
||||
MonitorState::Excluded => (
|
||||
Span::styled("⊘ ", Style::default().fg(theme::RED)),
|
||||
"Excluded",
|
||||
Style::default().fg(theme::RED),
|
||||
),
|
||||
MonitorState::Unspecified => (
|
||||
Span::styled("? ", Style::default().fg(theme::GRAY)),
|
||||
"Unknown",
|
||||
Style::default().fg(theme::GRAY),
|
||||
),
|
||||
};
|
||||
|
||||
let lines = vec![
|
||||
|
||||
Reference in New Issue
Block a user