added input modes

This commit is contained in:
2025-08-05 20:45:11 +02:00
parent 6c05c76f3f
commit a2d14ca5ce
+59 -36
View File
@@ -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<StationInfo>,
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<ListItem> = 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(())
}