added search field

This commit is contained in:
2025-08-05 19:36:17 +02:00
parent 6a15a5de74
commit 6c05c76f3f
+40 -8
View File
@@ -20,6 +20,8 @@ pub struct App {
exit: bool, exit: bool,
stations: Vec<StationInfo>, stations: Vec<StationInfo>,
station_list_state: ListState, station_list_state: ListState,
filtered_stations: Vec<StationInfo>,
search_query: String,
} }
impl Default for App { impl Default for App {
@@ -32,12 +34,13 @@ impl Default for App {
state.select(Some(0)); state.select(Some(0));
state state
}, },
filtered_stations: Vec::new(),
search_query: String::new(),
} }
} }
} }
impl App { impl App {
/// runs the application's main loop until the user quits
pub fn run(&mut self, terminal: &mut DefaultTerminal) -> Result<()> { pub fn run(&mut self, terminal: &mut DefaultTerminal) -> Result<()> {
while !self.exit { while !self.exit {
terminal.draw(|frame| self.draw(frame))?; terminal.draw(|frame| self.draw(frame))?;
@@ -59,7 +62,7 @@ impl App {
// Render the left block (e.g., station selection) // Render the left block (e.g., station selection)
let max_name_len = left.width.saturating_sub(4) as usize; let max_name_len = left.width.saturating_sub(4) as usize;
let station_items: Vec<ListItem> = self let station_items: Vec<ListItem> = self
.stations .filtered_stations
.iter() .iter()
.map(|s| { .map(|s| {
let name = if s.name.len() > max_name_len { let name = if s.name.len() > max_name_len {
@@ -77,10 +80,12 @@ impl App {
.highlight_style(ratatui::style::Style::default().reversed()); .highlight_style(ratatui::style::Style::default().reversed());
frame.render_stateful_widget(stations_list, left, &mut self.station_list_state.clone()); 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"), bottom_right);
frame.render_widget(Block::bordered().title("Played Songs"), top_right);
let search = Paragraph::new(format!("Search: {}", self.search_query))
.block(Block::bordered().title("Search"));
frame.render_widget(search, top_right);
let station = self let station = self
.station_list_state .station_list_state
@@ -95,13 +100,10 @@ impl App {
.block(Block::bordered().title("Info")); .block(Block::bordered().title("Info"));
frame.render_widget(paragraph, bottom_right); frame.render_widget(paragraph, bottom_right);
// frame.render_widget(Block::bordered().title("Info / Controls"), bottom_right);
} }
fn handle_events(&mut self) -> io::Result<()> { fn handle_events(&mut self) -> io::Result<()> {
match event::read()? { match event::read()? {
// it's important to check that the event is a key press event as
// crossterm also emits key release and repeat events on Windows.
Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
self.handle_key_event(key_event) self.handle_key_event(key_event)
} }
@@ -125,6 +127,14 @@ impl App {
self.station_list_state.select(Some(prev)); self.station_list_state.select(Some(prev));
} }
} }
KeyCode::Char(c) => {
self.search_query.push(c);
self.update_filter();
}
KeyCode::Backspace => {
self.search_query.pop();
self.update_filter();
}
_ => {} _ => {}
} }
} }
@@ -145,6 +155,8 @@ impl App {
.await .await
.map_err(|e| eyre!("Failed to fetch station: {e}"))?; .map_err(|e| eyre!("Failed to fetch station: {e}"))?;
self.filtered_stations = self.stations.clone();
eprintln!("Loaded {} stations", stations.len()); eprintln!("Loaded {} stations", stations.len());
if self.stations.is_empty() { if self.stations.is_empty() {
self.stations.push(StationInfo { self.stations.push(StationInfo {
@@ -163,4 +175,24 @@ impl App {
Ok(()) Ok(())
} }
fn update_filter(&mut self) {
if self.search_query.is_empty() {
self.filtered_stations = self.stations.clone();
} else {
let query = self.search_query.to_lowercase();
self.filtered_stations = self
.stations
.iter()
.filter(|s| s.name.to_lowercase().contains(&query))
.cloned()
.collect();
}
if self.filtered_stations.is_empty() {
self.station_list_state.select(None);
} else {
self.station_list_state.select(Some(0));
}
}
} }