centralized general movement

This commit is contained in:
Priec
2025-08-27 01:06:54 +02:00
parent 18393ff661
commit d641ad1bbb
9 changed files with 451 additions and 61 deletions

View File

@@ -371,6 +371,58 @@ impl EventHandler {
match current_mode {
AppMode::General => {
// Map keys to MovementAction
let movement_action = if let Some(act) =
config.get_general_action(key_event.code, key_event.modifiers)
{
use crate::movement::MovementAction;
match act {
"up" => Some(MovementAction::Up),
"down" => Some(MovementAction::Down),
"left" => Some(MovementAction::Left),
"right" => Some(MovementAction::Right),
"next" => Some(MovementAction::Next),
"previous" => Some(MovementAction::Previous),
"select" => Some(MovementAction::Select),
"esc" => Some(MovementAction::Esc),
_ => None,
}
} else {
None
};
// Let the current page handle decoupled movement first
if let Some(ma) = movement_action {
match &mut router.current {
Page::AddTable(state) => {
if state.handle_movement(ma) {
// Keep UI focus consistent with inputs vs. outer elements
use crate::state::pages::add_table::AddTableFocus;
let is_canvas_input = matches!(
state.current_focus,
AddTableFocus::InputTableName
| AddTableFocus::InputColumnName
| AddTableFocus::InputColumnType
);
app_state.ui.focus_outside_canvas = !is_canvas_input;
return Ok(EventOutcome::Ok(String::new()));
}
}
Page::Admin(state) => {
if state.handle_movement(app_state, ma) {
return Ok(EventOutcome::Ok(String::new()));
}
}
Page::Intro(state) => {
if state.handle_movement(ma) {
return Ok(EventOutcome::Ok(String::new()));
}
}
_ => {}
}
}
// Optional page-specific handlers (non-movement or rich actions)
if let Page::Admin(admin_state) = &mut router.current {
if auth_state.role.as_deref() == Some("admin") {
if admin_nav::handle_admin_navigation(
@@ -401,7 +453,7 @@ impl EventHandler {
router,
) {
return Ok(EventOutcome::Ok(
self.command_message.clone(),
self.command_message.clone(),
));
}
@@ -423,16 +475,25 @@ impl EventHandler {
}
}
let nav_outcome = navigation::handle_navigation_event(
key_event,
config,
app_state,
router,
&mut self.command_mode,
&mut self.command_input,
&mut self.command_message,
&mut self.navigation_state,
).await;
// Generic navigation for the rest (Intro/Login/Register/Form)
let nav_outcome = if matches!(
&router.current,
Page::Admin(_) | Page::AddTable(_) | Page::AddLogic(_)
) {
Ok(EventOutcome::Ok(String::new()))
} else {
navigation::handle_navigation_event(
key_event,
config,
app_state,
router,
&mut self.command_mode,
&mut self.command_input,
&mut self.command_message,
&mut self.navigation_state,
).await
};
match nav_outcome {
Ok(EventOutcome::ButtonSelected { context, index }) => {
let message = match context {
@@ -443,14 +504,8 @@ impl EventHandler {
index,
);
if let Page::Admin(admin_state) = &mut router.current {
if !app_state
.profile_tree
.profiles
.is_empty()
{
admin_state
.profile_list_state
.select(Some(0));
if !app_state.profile_tree.profiles.is_empty() {
admin_state.profile_list_state.select(Some(0));
}
}
format!("Intro Option {} selected", index)
@@ -506,8 +561,9 @@ impl EventHandler {
}
format!("Admin Option {} selected", index)
}
UiContext::Dialog => "Internal error: Unexpected dialog state"
.to_string(),
UiContext::Dialog => {
"Internal error: Unexpected dialog state".to_string()
}
};
return Ok(EventOutcome::Ok(message));
}
@@ -515,37 +571,6 @@ impl EventHandler {
}
}
AppMode::General => {
match &router.current {
Page::Form(_)
| Page::Login(_)
| Page::Register(_)
| Page::AddTable(_)
| Page::AddLogic(_) => {
if !app_state.ui.focus_outside_canvas {
if let Some(editor) = &mut app_state.form_editor {
editor.set_keymap(config.build_canvas_keymap());
match editor.handle_key_event(key_event) {
KeyEventOutcome::Consumed(Some(msg)) => {
return Ok(EventOutcome::Ok(msg));
}
KeyEventOutcome::Consumed(None) => {
return Ok(EventOutcome::Ok(String::new()));
}
KeyEventOutcome::Pending => {
return Ok(EventOutcome::Ok(String::new()));
}
KeyEventOutcome::NotMatched => {
// fall through to client actions
}
}
}
}
}
_ => {}
}
}
AppMode::Command => {
if config.is_exit_command_mode(key_code, modifiers) {
self.command_input.clear();