diff --git a/src/radio/app.rs b/src/radio/app.rs index b4d3bb5..8b42715 100644 --- a/src/radio/app.rs +++ b/src/radio/app.rs @@ -15,6 +15,12 @@ use std::io::{self}; use crate::radio::station::StationInfo; use ratatui::widgets::{List, ListItem, ListState}; +#[derive(Debug, PartialEq)] +pub enum InputMode { + Normal, + Search, +} + #[derive(Debug)] pub struct App { exit: bool, @@ -22,6 +28,7 @@ pub struct App { station_list_state: ListState, filtered_stations: Vec, search_query: String, + input_mode: InputMode, } impl Default for App { @@ -35,6 +42,7 @@ impl Default for App { state }, filtered_stations: Vec::new(), + input_mode: InputMode::Normal, search_query: String::new(), } } @@ -57,10 +65,13 @@ impl App { .areas(area); let [top_right, bottom_right] = - Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]).areas(right); + Layout::vertical([Constraint::Percentage(10), Constraint::Percentage(90)]).areas(right); + + let [top_left, bottom_left] = + Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]).areas(left); // Render the left block (e.g., station selection) - let max_name_len = left.width.saturating_sub(4) as usize; + let max_name_len = top_left.width.saturating_sub(4) as usize; let station_items: Vec = self .filtered_stations .iter() @@ -79,27 +90,28 @@ impl App { .highlight_symbol(">>") .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("Played Songs"), bottom_right); - - let search = Paragraph::new(format!("Search: {}", self.search_query)) - .block(Block::bordered().title("Search")); - frame.render_widget(search, top_right); + frame.render_stateful_widget( + stations_list, + top_left, + &mut self.station_list_state.clone(), + ); let station = self .station_list_state .selected() - .and_then(|i| self.stations.get(i)); - + .and_then(|i| self.filtered_stations.get(i)); let paragraph = Paragraph::new( station .map(|s| format!("Now selected: {}\n{}", s.name, s.url)) .unwrap_or_else(|| "No station selected".into()), ) .block(Block::bordered().title("Info")); + frame.render_widget(paragraph, bottom_left); - frame.render_widget(paragraph, bottom_right); + let search = Paragraph::new(format!("{}", self.search_query)) + .block(Block::bordered().title("Search")); + frame.render_widget(search, top_right); + frame.render_widget(Block::bordered().title("Played Songs"), bottom_right); } fn handle_events(&mut self) -> io::Result<()> { @@ -113,29 +125,41 @@ impl App { } fn handle_key_event(&mut self, key_event: KeyEvent) { - match key_event.code { - KeyCode::Char('q') => self.exit(), - KeyCode::Down | KeyCode::Char('j') => { - 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)); + match self.input_mode { + InputMode::Normal => match key_event.code { + KeyCode::Char('/') => { + self.input_mode = InputMode::Search; + self.search_query.clear(); } - } - KeyCode::Up | KeyCode::Char('k') => { - if let Some(i) = self.station_list_state.selected() { - let prev = i.saturating_sub(1); - self.station_list_state.select(Some(prev)); + KeyCode::Char('q') => self.exit(), + KeyCode::Down | KeyCode::Char('j') => { + 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::Char(c) => { - self.search_query.push(c); - self.update_filter(); - } - KeyCode::Backspace => { - self.search_query.pop(); - self.update_filter(); - } - _ => {} + KeyCode::Up | KeyCode::Char('k') => { + if let Some(i) = self.station_list_state.selected() { + let prev = i.saturating_sub(1); + self.station_list_state.select(Some(prev)); + } + } + _ => {} + }, + InputMode::Search => match key_event.code { + KeyCode::Char(c) => { + self.search_query.push(c); + self.update_filter(); + } + KeyCode::Backspace => { + self.search_query.pop(); + self.update_filter(); + } + KeyCode::Esc | KeyCode::Enter => { + self.input_mode = InputMode::Normal; + } + _ => {} + }, } } @@ -155,9 +179,6 @@ 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 { name: "No stations found".into(), @@ -173,6 +194,8 @@ impl App { }) .collect(); + self.update_filter(); + Ok(()) }