From 6c05c76f3ff6c7d2809b092eb46f5502426e36e3 Mon Sep 17 00:00:00 2001 From: mace Date: Tue, 5 Aug 2025 19:36:17 +0200 Subject: [PATCH] added search field --- src/radio/app.rs | 48 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/radio/app.rs b/src/radio/app.rs index 9e77250..b4d3bb5 100644 --- a/src/radio/app.rs +++ b/src/radio/app.rs @@ -20,6 +20,8 @@ pub struct App { exit: bool, stations: Vec, station_list_state: ListState, + filtered_stations: Vec, + search_query: String, } impl Default for App { @@ -32,12 +34,13 @@ impl Default for App { state.select(Some(0)); state }, + filtered_stations: Vec::new(), + search_query: String::new(), } } } impl App { - /// runs the application's main loop until the user quits pub fn run(&mut self, terminal: &mut DefaultTerminal) -> Result<()> { while !self.exit { terminal.draw(|frame| self.draw(frame))?; @@ -59,7 +62,7 @@ impl App { // Render the left block (e.g., station selection) let max_name_len = left.width.saturating_sub(4) as usize; let station_items: Vec = self - .stations + .filtered_stations .iter() .map(|s| { let name = if s.name.len() > max_name_len { @@ -77,10 +80,12 @@ impl App { .highlight_style(ratatui::style::Style::default().reversed()); 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); + frame.render_widget(Block::bordered().title("Played Songs"), bottom_right); + + let search = Paragraph::new(format!("Search: {}", self.search_query)) + .block(Block::bordered().title("Search")); + frame.render_widget(search, top_right); let station = self .station_list_state @@ -95,13 +100,10 @@ impl App { .block(Block::bordered().title("Info")); frame.render_widget(paragraph, bottom_right); - // frame.render_widget(Block::bordered().title("Info / Controls"), bottom_right); } fn handle_events(&mut self) -> io::Result<()> { 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 => { self.handle_key_event(key_event) } @@ -125,6 +127,14 @@ impl App { 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 .map_err(|e| eyre!("Failed to fetch station: {e}"))?; + self.filtered_stations = self.stations.clone(); + eprintln!("Loaded {} stations", stations.len()); if self.stations.is_empty() { self.stations.push(StationInfo { @@ -163,4 +175,24 @@ impl App { 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)); + } + } }