use ratatui::{
Frame,
layout::{Constraint, Direction, Layout, Rect},
style::{Modifier, Style},
text::{Line, Span},
widgets::{List, ListItem, ListState, Paragraph},
};
use super::layout::{styled_block, truncate};
use crate::app::{AppState, Focus};
pub fn render_tracklist(frame: &mut Frame, state: &AppState, area: Rect) {
let focused = state.focus == Focus::TrackList;
let t = &state.theme;
let has_filter = state.filter_active || !state.tracklist_filter.is_empty();
let pl_name = state
.library
.playlist(state.active_playlist)
.map(|p| p.name.as_str())
.unwrap_or("Tracks");
let title = format!(" {} ", pl_name);
let block = styled_block(&title, focused, t).style(t.apply_panel_bg(Style::default()));
let inner = block.inner(area);
frame.render_widget(block, area);
let (list_rect, filter_rect) = if has_filter {
let s = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(0), Constraint::Length(1)])
.split(inner);
(s[0], Some(s[1]))
} else {
(inner, None)
};
if let Some(fr) = filter_rect {
let prefix_style = if state.filter_active {
Style::default().fg(t.accent).add_modifier(Modifier::BOLD)
} else {
Style::default().fg(t.text_dim)
};
frame.render_widget(
Paragraph::new(Line::from(vec![
Span::styled("/ ", prefix_style),
Span::styled(state.tracklist_filter.as_str(), Style::default().fg(t.text)),
Span::styled(
if state.filter_active { "█" } else { "" },
Style::default().fg(t.accent),
),
])),
fr,
);
}
let header = ListItem::new(Line::from(Span::styled(
format!(" {:<4} {:<}", "#", "Track"),
Style::default().fg(t.subtle).add_modifier(Modifier::BOLD),
)));
let tracks = state.active_tracks();
let items: Vec<ListItem> = tracks
.iter()
.enumerate()
.map(|(i, track)| {
let is_playing = state
.now_playing
.and_then(|np| state.queue.get(np))
.map(|qt| qt.id == track.id)
.unwrap_or(false);
let num = Span::styled(
format!(" {:>3} ", i + 1),
Style::default().fg(if is_playing { t.accent } else { t.subtle }),
);
let title_span = Span::styled(
truncate(
&track.display(),
(list_rect.width as usize).saturating_sub(8),
),
if is_playing {
Style::default()
.fg(t.now_playing)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(t.text_dim)
},
);
ListItem::new(Line::from(vec![num, title_span]))
})
.collect();
let all_items: Vec<ListItem> = std::iter::once(header).chain(items).collect();
let mut list_state = ListState::default();
if focused {
list_state.select(Some(state.tracklist_cursor + 1));
}
frame.render_stateful_widget(
List::new(all_items).highlight_style(
Style::default()
.fg(t.text)
.bg(t.panel_bg)
.add_modifier(Modifier::BOLD),
),
list_rect,
&mut list_state,
);
}