diff --git a/client/src/config/config.rs b/client/src/config/config.rs index 6294983..ea0d4ec 100644 --- a/client/src/config/config.rs +++ b/client/src/config/config.rs @@ -71,7 +71,7 @@ impl Config { } /// Helper function to get an action for a key in a specific mode. - fn get_action_for_key_in_mode<'a>( + pub fn get_action_for_key_in_mode<'a>( &self, mode_bindings: &'a HashMap>, key: KeyCode, diff --git a/client/src/modes/handlers.rs b/client/src/modes/handlers.rs index f4609c9..1ff5222 100644 --- a/client/src/modes/handlers.rs +++ b/client/src/modes/handlers.rs @@ -1,5 +1,6 @@ // src/client/modes/handlers.rs pub mod event; pub mod edit; +pub mod common; pub mod command_mode; pub mod read_only; diff --git a/client/src/modes/handlers/command_mode.rs b/client/src/modes/handlers/command_mode.rs index 97937d7..6252246 100644 --- a/client/src/modes/handlers/command_mode.rs +++ b/client/src/modes/handlers/command_mode.rs @@ -4,7 +4,7 @@ use crossterm::event::{KeyEvent, KeyCode, KeyModifiers}; use crate::tui::terminal::AppTerminal; use crate::config::config::Config; use crate::ui::handlers::form::FormState; -use common::proto::multieko2::adresar::{PostAdresarRequest, PutAdresarRequest}; +use super::common; pub async fn handle_command_event( key: KeyEvent, @@ -17,6 +17,7 @@ pub async fn handle_command_event( current_position: &mut u64, total_count: u64, ) -> Result<(bool, String, bool), Box> { + // Return value: (should_exit, message, should_exit_command_mode) // Exit command mode (via configurable keybinding) @@ -82,121 +83,34 @@ async fn process_command( // For debugging eprintln!("Command: '{}', Action: '{}'", command, action); - match action { "save" => { - let is_new = *current_position == total_count + 1; - - let message = if is_new { - let post_request = PostAdresarRequest { - firma: form_state.values[0].clone(), - kz: form_state.values[1].clone(), - drc: form_state.values[2].clone(), - ulica: form_state.values[3].clone(), - psc: form_state.values[4].clone(), - mesto: form_state.values[5].clone(), - stat: form_state.values[6].clone(), - banka: form_state.values[7].clone(), - ucet: form_state.values[8].clone(), - skladm: form_state.values[9].clone(), - ico: form_state.values[10].clone(), - kontakt: form_state.values[11].clone(), - telefon: form_state.values[12].clone(), - skladu: form_state.values[13].clone(), - fax: form_state.values[14].clone(), - }; - let response = app_terminal.post_adresar(post_request).await?; - let new_total = app_terminal.get_adresar_count().await?; - *current_position = new_total; - form_state.id = response.into_inner().id; - "New entry created".to_string() - } else { - let put_request = PutAdresarRequest { - id: form_state.id, - firma: form_state.values[0].clone(), - kz: form_state.values[1].clone(), - drc: form_state.values[2].clone(), - ulica: form_state.values[3].clone(), - psc: form_state.values[4].clone(), - mesto: form_state.values[5].clone(), - stat: form_state.values[6].clone(), - banka: form_state.values[7].clone(), - ucet: form_state.values[8].clone(), - skladm: form_state.values[9].clone(), - ico: form_state.values[10].clone(), - kontakt: form_state.values[11].clone(), - telefon: form_state.values[12].clone(), - skladu: form_state.values[13].clone(), - fax: form_state.values[14].clone(), - }; - let _ = app_terminal.put_adresar(put_request).await?; - "Entry updated".to_string() - }; - - *is_saved = true; - form_state.has_unsaved_changes = false; + let message = common::save( + form_state, + app_terminal, + is_saved, + current_position, + total_count, + ).await?; command_input.clear(); return Ok((false, message, true)); }, - "quit" => { - if form_state.has_unsaved_changes { - command_input.clear(); - return Ok((false, "Unsaved changes! Use :q! to force quit or :w to save".to_string(), true)); - } - command_input.clear(); - return Ok((true, "Exiting application".to_string(), true)); - }, "force_quit" => { + let (should_exit, message) = common::force_quit(); command_input.clear(); - return Ok((true, "Force quitting application".to_string(), true)); + return Ok((should_exit, message, true)); }, "save_and_quit" => { - let is_new = *current_position == total_count + 1; - - if is_new { - let post_request = PostAdresarRequest { - firma: form_state.values[0].clone(), - kz: form_state.values[1].clone(), - drc: form_state.values[2].clone(), - ulica: form_state.values[3].clone(), - psc: form_state.values[4].clone(), - mesto: form_state.values[5].clone(), - stat: form_state.values[6].clone(), - banka: form_state.values[7].clone(), - ucet: form_state.values[8].clone(), - skladm: form_state.values[9].clone(), - ico: form_state.values[10].clone(), - kontakt: form_state.values[11].clone(), - telefon: form_state.values[12].clone(), - skladu: form_state.values[13].clone(), - fax: form_state.values[14].clone(), - }; - let _ = app_terminal.post_adresar(post_request).await?; - } else { - let put_request = PutAdresarRequest { - id: form_state.id, - firma: form_state.values[0].clone(), - kz: form_state.values[1].clone(), - drc: form_state.values[2].clone(), - ulica: form_state.values[3].clone(), - psc: form_state.values[4].clone(), - mesto: form_state.values[5].clone(), - stat: form_state.values[6].clone(), - banka: form_state.values[7].clone(), - ucet: form_state.values[8].clone(), - skladm: form_state.values[9].clone(), - ico: form_state.values[10].clone(), - kontakt: form_state.values[11].clone(), - telefon: form_state.values[12].clone(), - skladu: form_state.values[13].clone(), - fax: form_state.values[14].clone(), - }; - let _ = app_terminal.put_adresar(put_request).await?; - } - + let (should_exit, message) = common::save_and_quit( + form_state, + app_terminal, + current_position, + total_count, + ).await?; command_input.clear(); - return Ok((true, "Saved and exiting application".to_string(), true)); + return Ok((should_exit, message, true)); }, + "unknown" => { let message = format!("Unknown command: {}", command); command_input.clear(); diff --git a/client/src/modes/handlers/common.rs b/client/src/modes/handlers/common.rs new file mode 100644 index 0000000..7353e56 --- /dev/null +++ b/client/src/modes/handlers/common.rs @@ -0,0 +1,124 @@ +// src/modes/handlers/common.rs + +use crate::tui::terminal::AppTerminal; +use crate::ui::handlers::form::FormState; +use common::proto::multieko2::adresar::{PostAdresarRequest, PutAdresarRequest}; + +/// Shared logic for saving the current form state +pub async fn save( + form_state: &mut FormState, + app_terminal: &mut AppTerminal, + is_saved: &mut bool, + current_position: &mut u64, + total_count: u64, +) -> Result> { + let is_new = *current_position == total_count + 1; + + let message = if is_new { + let post_request = PostAdresarRequest { + firma: form_state.values[0].clone(), + kz: form_state.values[1].clone(), + drc: form_state.values[2].clone(), + ulica: form_state.values[3].clone(), + psc: form_state.values[4].clone(), + mesto: form_state.values[5].clone(), + stat: form_state.values[6].clone(), + banka: form_state.values[7].clone(), + ucet: form_state.values[8].clone(), + skladm: form_state.values[9].clone(), + ico: form_state.values[10].clone(), + kontakt: form_state.values[11].clone(), + telefon: form_state.values[12].clone(), + skladu: form_state.values[13].clone(), + fax: form_state.values[14].clone(), + }; + let response = app_terminal.post_adresar(post_request).await?; + let new_total = app_terminal.get_adresar_count().await?; + *current_position = new_total; + form_state.id = response.into_inner().id; + "New entry created".to_string() + } else { + let put_request = PutAdresarRequest { + id: form_state.id, + firma: form_state.values[0].clone(), + kz: form_state.values[1].clone(), + drc: form_state.values[2].clone(), + ulica: form_state.values[3].clone(), + psc: form_state.values[4].clone(), + mesto: form_state.values[5].clone(), + stat: form_state.values[6].clone(), + banka: form_state.values[7].clone(), + ucet: form_state.values[8].clone(), + skladm: form_state.values[9].clone(), + ico: form_state.values[10].clone(), + kontakt: form_state.values[11].clone(), + telefon: form_state.values[12].clone(), + skladu: form_state.values[13].clone(), + fax: form_state.values[14].clone(), + }; + let _ = app_terminal.put_adresar(put_request).await?; + "Entry updated".to_string() + }; + + *is_saved = true; + form_state.has_unsaved_changes = false; + Ok(message) +} + +/// Shared logic for force quitting the application +pub fn force_quit() -> (bool, String) { + (true, "Force quitting application".to_string()) +} + +/// Shared logic for saving and quitting +pub async fn save_and_quit( + form_state: &mut FormState, + app_terminal: &mut AppTerminal, + current_position: &mut u64, + total_count: u64, +) -> Result<(bool, String), Box> { + let is_new = *current_position == total_count + 1; + + if is_new { + let post_request = PostAdresarRequest { + firma: form_state.values[0].clone(), + kz: form_state.values[1].clone(), + drc: form_state.values[2].clone(), + ulica: form_state.values[3].clone(), + psc: form_state.values[4].clone(), + mesto: form_state.values[5].clone(), + stat: form_state.values[6].clone(), + banka: form_state.values[7].clone(), + ucet: form_state.values[8].clone(), + skladm: form_state.values[9].clone(), + ico: form_state.values[10].clone(), + kontakt: form_state.values[11].clone(), + telefon: form_state.values[12].clone(), + skladu: form_state.values[13].clone(), + fax: form_state.values[14].clone(), + }; + let _ = app_terminal.post_adresar(post_request).await?; + } else { + let put_request = PutAdresarRequest { + id: form_state.id, + firma: form_state.values[0].clone(), + kz: form_state.values[1].clone(), + drc: form_state.values[2].clone(), + ulica: form_state.values[3].clone(), + psc: form_state.values[4].clone(), + mesto: form_state.values[5].clone(), + stat: form_state.values[6].clone(), + banka: form_state.values[7].clone(), + ucet: form_state.values[8].clone(), + skladm: form_state.values[9].clone(), + ico: form_state.values[10].clone(), + kontakt: form_state.values[11].clone(), + telefon: form_state.values[12].clone(), + skladu: form_state.values[13].clone(), + fax: form_state.values[14].clone(), + }; + let _ = app_terminal.put_adresar(put_request).await?; + } + + Ok((true, "Saved and exiting application".to_string())) +} diff --git a/client/src/modes/handlers/edit.rs b/client/src/modes/handlers/edit.rs index 0bf924b..ea2fcdb 100644 --- a/client/src/modes/handlers/edit.rs +++ b/client/src/modes/handlers/edit.rs @@ -5,6 +5,7 @@ use crate::tui::terminal::AppTerminal; use crate::config::config::Config; use crate::ui::handlers::form::FormState; use crate::config::key_sequences::KeySequenceTracker; +use super::common; // This function is called from event.rs and doesn't need to handle mode transitions anymore pub async fn handle_edit_event_internal( @@ -13,13 +14,20 @@ pub async fn handle_edit_event_internal( form_state: &mut FormState, ideal_cursor_column: &mut usize, command_message: &mut String, + app_terminal: &mut AppTerminal, // Add these parameters + is_saved: &mut bool, + current_position: &mut u64, + total_count: u64, ) -> Result> { - // Try to match against configured Edit mode action mappings first if let Some(action) = config.get_edit_action_for_key(key.code, key.modifiers) { return execute_edit_action( action, form_state, ideal_cursor_column, + app_terminal, // Pass them here + is_saved, + current_position, + total_count, ).await; } @@ -111,8 +119,21 @@ async fn execute_edit_action( action: &str, form_state: &mut FormState, ideal_cursor_column: &mut usize, + app_terminal: &mut AppTerminal, + is_saved: &mut bool, + current_position: &mut u64, + total_count: u64, ) -> Result> { match action { + "save" => { + common::save( + form_state, + app_terminal, + is_saved, + current_position, + total_count, + ).await + }, // Navigation actions "move_left" => { form_state.current_cursor_pos = form_state.current_cursor_pos.saturating_sub(1); diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index e7e6c21..4053b68 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -7,6 +7,7 @@ use crate::config::config::Config; use crate::ui::handlers::form::FormState; use crate::modes::handlers::{edit, command_mode, read_only}; use crate::config::key_sequences::KeySequenceTracker; +use super::common; pub struct EventHandler { pub command_mode: bool, @@ -42,6 +43,39 @@ impl EventHandler { current_position: &mut u64, ) -> Result<(bool, String), Box> { if let Event::Key(key) = event { + if let Some(action) = config.get_action_for_key_in_mode( + &config.keybindings.common, + key.code, + key.modifiers + ) { + match action { + "save" => { + let message = common::save( + form_state, + app_terminal, + is_saved, + current_position, + total_count, + ).await?; + return Ok((false, message)); + }, + "force_quit" => { + let (should_exit, message) = common::force_quit(); + return Ok((should_exit, message)); + }, + "save_and_quit" => { + let (should_exit, message) = common::save_and_quit( + form_state, + app_terminal, + current_position, + total_count, + ).await?; + return Ok((should_exit, message)); + }, + _ => {} + } + } + // Handle command mode with highest priority if self.command_mode { let (should_exit, message, exit_command_mode) = command_mode::handle_command_event( @@ -98,6 +132,10 @@ impl EventHandler { form_state, &mut self.ideal_cursor_column, &mut self.command_message, + app_terminal, + is_saved, + current_position, + total_count, ).await?; self.key_sequence_tracker.reset();