diff --git a/client/src/modes/general.rs b/client/src/modes/general.rs index aa1c875..d859ed8 100644 --- a/client/src/modes/general.rs +++ b/client/src/modes/general.rs @@ -1,2 +1,3 @@ // src/client/modes/general.rs pub mod navigation; +pub mod dialog; diff --git a/client/src/modes/general/dialog.rs b/client/src/modes/general/dialog.rs new file mode 100644 index 0000000..79e81c6 --- /dev/null +++ b/client/src/modes/general/dialog.rs @@ -0,0 +1,71 @@ +// src/modes/general/dialog.rs + +use crossterm::event::{Event, KeyCode, KeyEvent}; +use crate::config::binds::config::Config; +use crate::state::state::AppState; +use crate::modes::handlers::event::EventOutcome; // Use EventOutcome from event handler + +/// Handles key events specifically when a dialog is active. +/// Returns Some(Result) if the event was handled (consumed), +/// otherwise returns None. +pub async fn handle_dialog_event( + event: &Event, + config: &Config, + app_state: &mut AppState, +) -> Option>> { + if let Event::Key(key) = event { + // Always allow Esc to dismiss + if key.code == KeyCode::Esc { + app_state.hide_dialog(); + return Some(Ok(EventOutcome::Ok("Dialog dismissed".to_string()))); + } + + // Check general bindings for dialog actions + if let Some(action) = config.get_general_action(key.code, key.modifiers) { + match action { + "move_up" | "previous_option" => { + let current_index = app_state.ui.dialog.dialog_active_button_index; + let num_buttons = app_state.ui.dialog.dialog_buttons.len(); + if num_buttons > 0 && current_index < num_buttons - 1 { + app_state.ui.dialog.dialog_active_button_index += 1; + } + return Some(Ok(EventOutcome::Ok(String::new()))); + } + "move_down" | "next_option" => { + let current_index = app_state.ui.dialog.dialog_active_button_index; + if current_index > 0 { + app_state.ui.dialog.dialog_active_button_index -= 1; + } + return Some(Ok(EventOutcome::Ok(String::new()))); + + } + "select" => { + let selected_index = app_state.ui.dialog.dialog_active_button_index; + let selected_label = app_state.get_active_dialog_button_label().unwrap_or("").to_string(); + let mut message = format!("Dialog '{}' selected", selected_label); + + // --- Add specific actions based on button index or label --- + if selected_label.eq_ignore_ascii_case("menu") { + app_state.ui.show_login = false; + app_state.ui.show_intro = true; + // focus_outside_canvas is handled by hide_dialog + message = "Returning to menu".to_string(); + } else if selected_label.eq_ignore_ascii_case("exit") { + app_state.hide_dialog(); + return Some(Ok(EventOutcome::Exit("Exiting via dialog".to_string()))); + } + // --- End specific actions --- + app_state.hide_dialog(); // Hide dialog after processing selection + return Some(Ok(EventOutcome::Ok(message))); // Consume event + } + _ => {} // Ignore other general actions when dialog is shown + } + } + // If it was a key event but not handled above, consume it + Some(Ok(EventOutcome::Ok(String::new()))) + } else { + // If it wasn't a key event, consume it too while dialog is active + Some(Ok(EventOutcome::Ok(String::new()))) + } +} + diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index b1f6872..8f9557a 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -17,7 +17,7 @@ use crate::tui::functions::{intro, admin}; use crate::modes::{ common::command_mode, canvas::{edit, read_only, common_mode}, - general::navigation, + general::{navigation, dialog}, }; use crate::config::binds::key_sequences::KeySequenceTracker; use crate::modes::handlers::mode_manager::{ModeManager, AppMode}; @@ -72,58 +72,12 @@ impl EventHandler { let current_mode = ModeManager::derive_mode(app_state, self); app_state.update_mode(current_mode); - // --- DIALOG MODALITY CHECK --- + // --- DIALOG MODALITY --- // If a dialog is showing, intercept and handle ONLY dialog inputs. if app_state.ui.dialog.dialog_show { - if let Event::Key(key) = event { - // Always allow Esc to dismiss - if key.code == KeyCode::Esc { - app_state.hide_dialog(); - return Ok(EventOutcome::Ok("Dialog dismissed".to_string())); - } - - // Check general bindings for dialog actions - if let Some(action) = config.get_general_action(key.code, key.modifiers) { - match action { - "move_down" | "move_right" => { - let current_index = app_state.ui.dialog.dialog_active_button_index; - let num_buttons = app_state.ui.dialog.dialog_buttons.len(); - if num_buttons > 0 && current_index < num_buttons - 1 { - app_state.ui.dialog.dialog_active_button_index += 1; - } - return Ok(EventOutcome::Ok(String::new())); // Consume event - } - "move_up" | "move_left" => { - let current_index = app_state.ui.dialog.dialog_active_button_index; - if current_index > 0 { - app_state.ui.dialog.dialog_active_button_index -= 1; - } - return Ok(EventOutcome::Ok(String::new())); // Consume event - } - "select" => { - let selected_index = app_state.ui.dialog.dialog_active_button_index; - let selected_label = app_state.get_active_dialog_button_label().unwrap_or("").to_string(); - let mut message = format!("Dialog '{}' selected", selected_label); - - // --- Add specific actions based on button index or label --- - if selected_label.eq_ignore_ascii_case("menu") { - app_state.ui.show_login = false; - app_state.ui.show_intro = true; - // focus_outside_canvas is handled by hide_dialog - message = "Returning to menu".to_string(); - } else if selected_label.eq_ignore_ascii_case("exit") { - app_state.hide_dialog(); - return Ok(EventOutcome::Exit("Exiting via dialog".to_string())); - } - // --- End specific actions --- - app_state.hide_dialog(); // Hide dialog after processing selection - return Ok(EventOutcome::Ok(message)); // Consume event - } - _ => {} // Ignore other general actions when dialog is shown - } - } - } - // If dialog is shown, consume any event not handled above + if let Some(dialog_result) = dialog::handle_dialog_event(&event, config, app_state).await { + return dialog_result; + } return Ok(EventOutcome::Ok(String::new())); } // --- END DIALOG MODALITY CHECK ---