use flume::Sender; use ratatui::{ backend::Backend, layout::Rect, style::{Modifier, Style}, text::Span, widgets::{Block, BorderType, Borders, List, ListItem, ListState}, Frame, }; use crabidy_core::proto::crabidy::Queue as QueueData; use super::{ MessageFromUi, StatefulList, UiItem, UiItemKind, COLOR_PRIMARY, COLOR_PRIMARY_DARK, COLOR_RED, }; pub struct Queue { current_position: usize, list: Vec, list_state: ListState, tx: Sender, } impl Queue { pub fn new(tx: Sender) -> Self { Self { current_position: 0, list: Vec::new(), list_state: ListState::default(), tx, } } pub fn play_next(&self) { self.tx.send(MessageFromUi::NextTrack); } pub fn play_prev(&self) { self.tx.send(MessageFromUi::PrevTrack); } pub fn play_selected(&self) { if let Some(pos) = self.selected() { self.tx.send(MessageFromUi::SetCurrentTrack(pos)); } } pub fn select_current(&mut self) { self.select(Some(self.current_position)); } pub fn remove_track(&mut self) { if let Some(pos) = self.selected() { // FIXME: mark multiple tracks on queue and remove them self.tx.send(MessageFromUi::RemoveTracks(vec![pos])); } } pub fn update_position(&mut self, pos: usize) { self.current_position = pos; } pub fn update_queue(&mut self, queue: QueueData) { self.current_position = queue.current_position as usize; self.list = queue .tracks .iter() .enumerate() .map(|(i, t)| UiItem { uuid: t.uuid.clone(), title: format!("{} - {}", t.artist, t.title), kind: UiItemKind::Track, marked: false, is_queable: false, }) .collect(); self.update_selection(); } pub fn render(&mut self, f: &mut Frame, area: Rect, focused: bool) { let queue_items: Vec = self .list .iter() .enumerate() .map(|(idx, item)| { let active = idx == self.current_position; let title = if active { format!("> {}", item.title) } else { item.title.to_string() }; let style = if active { Style::default().fg(COLOR_RED).add_modifier(Modifier::BOLD) } else { Style::default() }; ListItem::new(Span::from(title)).style(style) }) .collect(); let queue_list = List::new(queue_items) .block( Block::default() .borders(Borders::ALL) .border_type(BorderType::Rounded) .border_style(Style::default().fg(if focused { COLOR_PRIMARY } else { COLOR_PRIMARY_DARK })) .title("Queue"), ) .highlight_style(Style::default().bg(if focused { COLOR_PRIMARY } else { COLOR_PRIMARY_DARK })); f.render_stateful_widget(queue_list, area, &mut self.list_state); } } impl StatefulList for Queue { fn get_size(&self) -> usize { self.list.len() } fn select(&mut self, idx: Option) { self.list_state.select(idx); } fn selected(&self) -> Option { self.list_state.selected() } }