channel list

This commit is contained in:
2025-08-03 21:58:03 +02:00
parent 3e36f25582
commit 6a15a5de74
2 changed files with 45 additions and 32 deletions
+1
View File
@@ -5,6 +5,7 @@ use iradio::radio::{app::App, tui};
async fn main() -> Result<()> {
color_eyre::install()?;
let mut terminal = tui::init()?;
terminal.clear()?;
let mut app = App::default();
app.load_stations().await?;
let app_result = app.run(&mut terminal);
+44 -32
View File
@@ -7,20 +7,33 @@ use radiobrowser::RadioBrowserAPI;
use ratatui::{
DefaultTerminal, Frame,
layout::{Constraint, Layout},
style::Stylize,
widgets::{Block, Paragraph},
};
use std::io::{self};
use crate::radio::station::StationInfo;
use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::{List, ListItem, ListState};
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct App {
exit: bool,
stations: Vec<StationInfo>,
selected_index: usize,
scroll_offset: usize,
station_list_state: ListState,
}
impl Default for App {
fn default() -> Self {
Self {
exit: false,
stations: Vec::new(),
station_list_state: {
let mut state = ListState::default();
state.select(Some(0));
state
},
}
}
}
impl App {
@@ -44,33 +57,36 @@ impl App {
Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]).areas(right);
// Render the left block (e.g., station selection)
let items: Vec<ListItem> = self
let max_name_len = left.width.saturating_sub(4) as usize;
let station_items: Vec<ListItem> = self
.stations
.iter()
.skip(self.scroll_offset)
.take(15) // max visible
.map(|s| ListItem::new(s.name.clone()))
.map(|s| {
let name = if s.name.len() > max_name_len {
format!("{}...", &s.name[..max_name_len.saturating_sub(3)])
} else {
s.name.clone()
};
ListItem::new(name.trim().to_owned())
})
.collect();
let mut list_state = ListState::default();
list_state.select(Some(self.selected_index - self.scroll_offset));
let stations_list = List::new(station_items)
.block(Block::bordered().title("Station Selection"))
.highlight_symbol(">>")
.highlight_style(ratatui::style::Style::default().reversed());
let list = List::new(items)
.block(Block::bordered().title("Stations"))
.highlight_style(
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
)
.highlight_symbol("");
frame.render_stateful_widget(list, left, &mut list_state);
frame.render_stateful_widget(stations_list, left, &mut self.station_list_state.clone());
// frame.render_widget(Block::bordered().title("Station Selection"), left);
// Render the top-right block (e.g., song history)
frame.render_widget(Block::bordered().title("Played Songs"), top_right);
let station = self.stations.get(self.selected_index);
let station = self
.station_list_state
.selected()
.and_then(|i| self.stations.get(i));
let paragraph = Paragraph::new(
station
.map(|s| format!("Now selected: {}\n{}", s.name, s.url))
@@ -98,19 +114,15 @@ impl App {
match key_event.code {
KeyCode::Char('q') => self.exit(),
KeyCode::Down | KeyCode::Char('j') => {
if self.selected_index + 1 < self.stations.len() {
self.selected_index += 1;
if self.selected_index >= self.scroll_offset + 15 {
self.scroll_offset += 1;
}
if let Some(i) = self.station_list_state.selected() {
let next = (i + 1).min(self.stations.len().saturating_sub(1));
self.station_list_state.select(Some(next));
}
}
KeyCode::Up | KeyCode::Char('k') => {
if self.selected_index > 0 {
self.selected_index -= 1;
if self.selected_index < self.scroll_offset {
self.scroll_offset = self.scroll_offset.saturating_sub(1);
}
if let Some(i) = self.station_list_state.selected() {
let prev = i.saturating_sub(1);
self.station_list_state.select(Some(prev));
}
}
_ => {}
@@ -127,7 +139,7 @@ impl App {
.map_err(|e| eyre!("Failed to create RadioBrowserAPI: {e}"))?;
let stations = api
.get_stations()
.country("DE")
.country("Germany")
.limit("50")
.send()
.await