added search field
This commit is contained in:
+40
-8
@@ -20,6 +20,8 @@ pub struct App {
|
||||
exit: bool,
|
||||
stations: Vec<StationInfo>,
|
||||
station_list_state: ListState,
|
||||
filtered_stations: Vec<StationInfo>,
|
||||
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<ListItem> = 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user