Files
komp_ac/client/src/pages/admin_panel/add_logic/event.rs

160 lines
6.5 KiB
Rust

// src/pages/admin_panel/add_logic/event.rs
use anyhow::Result;
use crate::config::binds::config::Config;
use crate::movement::{move_focus, MovementAction};
use crate::pages::admin_panel::add_logic::nav::SaveLogicResultSender;
use crate::pages::admin_panel::add_logic::state::{AddLogicFocus, AddLogicFormState};
use crate::components::common::text_editor::TextEditor;
use crate::services::grpc_client::GrpcClient;
use crate::state::app::state::AppState;
use crate::modes::handlers::event::EventOutcome;
use canvas::{AppMode as CanvasMode, DataProvider};
use crossterm::event::KeyEvent;
/// Focus traversal order for non-canvas navigation
const ADD_LOGIC_FOCUS_ORDER: [AddLogicFocus; 6] = [
AddLogicFocus::InputLogicName,
AddLogicFocus::InputTargetColumn,
AddLogicFocus::InputDescription,
AddLogicFocus::ScriptContentPreview,
AddLogicFocus::SaveButton,
AddLogicFocus::CancelButton,
];
/// Handles all AddLogic page-specific events.
/// Return a non-empty Ok(message) only when the page actually consumed the key,
/// otherwise return Ok("") to let global handling proceed.
pub fn handle_add_logic_event(
key_event: KeyEvent,
movement: Option<MovementAction>,
config: &Config,
app_state: &mut AppState,
add_logic_page: &mut AddLogicFormState,
grpc_client: GrpcClient,
save_logic_sender: SaveLogicResultSender,
) -> Result<EventOutcome> {
// 1) Script editor fullscreen mode
if add_logic_page.state.current_focus == AddLogicFocus::InsideScriptContent {
match key_event.code {
crossterm::event::KeyCode::Esc => {
add_logic_page.state.current_focus = AddLogicFocus::ScriptContentPreview;
add_logic_page.focus_outside_canvas = true;
return Ok(EventOutcome::Ok("Exited script editing.".to_string()));
}
_ => {
let changed = {
let mut editor_borrow =
add_logic_page.state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_page.state.editor_keybinding_mode,
&mut add_logic_page.state.vim_state,
)
};
if changed {
add_logic_page.state.has_unsaved_changes = true;
return Ok(EventOutcome::Ok("Script updated".to_string()));
}
return Ok(EventOutcome::Ok(String::new()));
}
}
}
// 2) Inside canvas: forward to FormEditor
let inside_canvas_inputs = matches!(
add_logic_page.state.current_focus,
AddLogicFocus::InputLogicName
| AddLogicFocus::InputTargetColumn
| AddLogicFocus::InputDescription
);
if inside_canvas_inputs {
// Only allow leaving the canvas with Down/Next when the form editor
// is in ReadOnly mode. In Edit mode, keep focus inside the canvas.
let in_edit_mode = add_logic_page.editor.mode() == CanvasMode::Edit;
if !in_edit_mode {
if let Some(ma) = movement {
let last_idx = add_logic_page
.editor
.data_provider()
.field_count()
.saturating_sub(1);
let at_last = add_logic_page.editor.current_field() >= last_idx;
if at_last && matches!(ma, MovementAction::Down | MovementAction::Next) {
add_logic_page.state.last_canvas_field = last_idx;
add_logic_page.state.current_focus = AddLogicFocus::ScriptContentPreview;
add_logic_page.focus_outside_canvas = true;
return Ok(EventOutcome::Ok("Moved to Script Preview".to_string()));
}
}
}
match add_logic_page.handle_key_event(key_event) {
canvas::keymap::KeyEventOutcome::Consumed(Some(msg)) => {
add_logic_page.sync_from_editor();
return Ok(EventOutcome::Ok(msg));
}
canvas::keymap::KeyEventOutcome::Consumed(None) => {
add_logic_page.sync_from_editor();
return Ok(EventOutcome::Ok("Input updated".into()));
}
canvas::keymap::KeyEventOutcome::Pending => {
return Ok(EventOutcome::Ok(String::new()));
}
canvas::keymap::KeyEventOutcome::NotMatched => {
// fall through
}
}
}
// 3) Outside canvas
if let Some(ma) = movement {
let mut current = add_logic_page.state.current_focus;
if move_focus(&ADD_LOGIC_FOCUS_ORDER, &mut current, ma) {
add_logic_page.state.current_focus = current;
add_logic_page.focus_outside_canvas = !matches!(
add_logic_page.state.current_focus,
AddLogicFocus::InputLogicName
| AddLogicFocus::InputTargetColumn
| AddLogicFocus::InputDescription
);
return Ok(EventOutcome::Ok(String::new()));
}
match ma {
MovementAction::Select => match add_logic_page.state.current_focus {
AddLogicFocus::ScriptContentPreview => {
add_logic_page.state.current_focus = AddLogicFocus::InsideScriptContent;
add_logic_page.focus_outside_canvas = false;
return Ok(EventOutcome::Ok(
"Fullscreen script editing. Esc to exit.".to_string(),
));
}
AddLogicFocus::SaveButton => {
if let Some(msg) = add_logic_page.state.save_logic() {
return Ok(EventOutcome::Ok(msg));
} else {
return Ok(EventOutcome::Ok("Saved (no changes)".to_string()));
}
}
AddLogicFocus::CancelButton => {
return Ok(EventOutcome::Ok("Cancelled Add Logic".to_string()));
}
_ => {}
},
MovementAction::Esc => {
if add_logic_page.state.current_focus == AddLogicFocus::ScriptContentPreview {
add_logic_page.state.current_focus = AddLogicFocus::InputDescription;
add_logic_page.focus_outside_canvas = false;
return Ok(EventOutcome::Ok("Back to Description".to_string()));
}
}
_ => {}
}
}
Ok(EventOutcome::Ok(String::new()))
}