Files
ferrosonic/src/app/input_server.rs
Jamie Hewitt b94c12a301 Refactor app/mod.rs into focused submodules
Split the 2495-line mod.rs into 10 files by concern:
- playback.rs: playback controls and track management
- cava.rs: cava process management and VT100 parsing
- input.rs: event dispatch and global keybindings
- input_artists.rs: artists page keyboard handling
- input_queue.rs: queue page keyboard handling
- input_playlists.rs: playlists page keyboard handling
- input_server.rs: server page keyboard handling
- input_settings.rs: settings page keyboard handling
- mouse.rs: all mouse click and scroll handling
- mod.rs: App struct, new(), run(), event_loop(), load_initial_data()

Pure code reorganization — no behavioral changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 23:41:43 +00:00

137 lines
5.8 KiB
Rust

use crossterm::event::{self, KeyCode};
use tracing::info;
use crate::error::Error;
use crate::subsonic::SubsonicClient;
use super::*;
impl App {
/// Handle server page keys
pub(super) async fn handle_server_key(&mut self, key: event::KeyEvent) -> Result<(), Error> {
let mut state = self.state.write().await;
let field = state.server_state.selected_field;
let is_text_field = field <= 2;
match key.code {
// Navigation - always works
KeyCode::Up => {
if field > 0 {
state.server_state.selected_field -= 1;
}
}
KeyCode::Down => {
if field < 4 {
state.server_state.selected_field += 1;
}
}
KeyCode::Tab => {
// Tab moves to next field, wrapping around
state.server_state.selected_field = (field + 1) % 5;
}
// Text input for text fields (0=URL, 1=Username, 2=Password)
KeyCode::Char(c) if is_text_field => match field {
0 => state.server_state.base_url.push(c),
1 => state.server_state.username.push(c),
2 => state.server_state.password.push(c),
_ => {}
},
KeyCode::Backspace if is_text_field => match field {
0 => {
state.server_state.base_url.pop();
}
1 => {
state.server_state.username.pop();
}
2 => {
state.server_state.password.pop();
}
_ => {}
},
// Enter activates buttons, ignored on text fields
KeyCode::Enter => {
match field {
3 => {
// Test connection
let url = state.server_state.base_url.clone();
let user = state.server_state.username.clone();
let pass = state.server_state.password.clone();
state.server_state.status = Some("Testing connection...".to_string());
drop(state);
match SubsonicClient::new(&url, &user, &pass) {
Ok(client) => match client.ping().await {
Ok(_) => {
let mut state = self.state.write().await;
state.server_state.status =
Some("Connection successful!".to_string());
}
Err(e) => {
let mut state = self.state.write().await;
state.server_state.status =
Some(format!("Connection failed: {}", e));
}
},
Err(e) => {
let mut state = self.state.write().await;
state.server_state.status = Some(format!("Invalid URL: {}", e));
}
}
return Ok(());
}
4 => {
// Save config and reconnect
info!(
"Saving config: url='{}', user='{}'",
state.server_state.base_url, state.server_state.username
);
state.config.base_url = state.server_state.base_url.clone();
state.config.username = state.server_state.username.clone();
state.config.password = state.server_state.password.clone();
let url = state.config.base_url.clone();
let user = state.config.username.clone();
let pass = state.config.password.clone();
match state.config.save_default() {
Ok(_) => {
info!("Config saved successfully");
state.server_state.status =
Some("Saved! Connecting...".to_string());
}
Err(e) => {
info!("Config save failed: {}", e);
state.server_state.status = Some(format!("Save failed: {}", e));
return Ok(());
}
}
drop(state);
// Create new client and load data
match SubsonicClient::new(&url, &user, &pass) {
Ok(client) => {
self.subsonic = Some(client);
self.load_initial_data().await;
let mut state = self.state.write().await;
state.server_state.status =
Some("Connected and loaded data!".to_string());
}
Err(e) => {
let mut state = self.state.write().await;
state.server_state.status =
Some(format!("Saved but connection failed: {}", e));
}
}
return Ok(());
}
_ => {} // Ignore Enter on text fields (handles paste with newlines)
}
}
_ => {}
}
Ok(())
}
}