diff --git a/client/src/components/auth/login.rs b/client/src/components/auth/login.rs index 7182956..63d3b71 100644 --- a/client/src/components/auth/login.rs +++ b/client/src/components/auth/login.rs @@ -6,6 +6,7 @@ use crate::{ components::common::dialog, state::state::AppState, }; +use crate::modes::handlers::mode_manager::AppMode; use ratatui::{ layout::{Alignment, Constraint, Direction, Layout, Rect, Margin}, style::{Style, Modifier, Color}, @@ -75,7 +76,12 @@ pub fn render_login( .split(chunks[2]); // Login Button - let login_active = !state.return_selected; + let login_button_index = 0; + let login_active = if app_state.current_mode == AppMode::General && app_state.ui.focus_outside_canvas { + app_state.general.selected_item == login_button_index + } else { + false + }; let mut login_style = Style::default().fg(theme.fg); let mut login_border = Style::default().fg(theme.border); if login_active { @@ -97,7 +103,12 @@ pub fn render_login( ); // Return Button - let return_active = state.return_selected; + let return_button_index = 1; // Assuming Return is the second general element + let return_active = if app_state.current_mode == AppMode::General && app_state.ui.focus_outside_canvas { + app_state.general.selected_item == return_button_index + } else { + false // Not active if focus is in canvas or other modes + }; let mut return_style = Style::default().fg(theme.fg); let mut return_border = Style::default().fg(theme.border); if return_active { diff --git a/client/src/functions/modes/read_only/auth_ro.rs b/client/src/functions/modes/read_only/auth_ro.rs index fd9d7a5..b54348e 100644 --- a/client/src/functions/modes/read_only/auth_ro.rs +++ b/client/src/functions/modes/read_only/auth_ro.rs @@ -2,6 +2,7 @@ use crate::config::binds::key_sequences::KeySequenceTracker; use crate::state::canvas_state::CanvasState; +use crate::state::state::AppState; use std::error::Error; #[derive(PartialEq)] @@ -13,6 +14,7 @@ enum CharType { pub async fn execute_action( action: &str, + app_state: &mut AppState, state: &mut S, ideal_cursor_column: &mut usize, key_sequence_tracker: &mut KeySequenceTracker, @@ -53,17 +55,28 @@ pub async fn execute_action( return Ok("No fields to navigate.".to_string()); } let current_field = state.current_field(); - let new_field = (state.current_field() + 1).min(num_fields - 1); - state.set_current_field(new_field); - let current_input = state.get_current_input(); - let max_cursor_pos = if current_input.is_empty() { - 0 + let last_field_index = num_fields - 1; + + if current_field == last_field_index { + // Already on the last field, move focus outside + app_state.ui.focus_outside_canvas = true; + app_state.general.selected_item = 0; // Focus first general item (e.g., Login button) + key_sequence_tracker.reset(); + Ok("Focus moved below canvas".to_string()) } else { - current_input.len().saturating_sub(1) - }; - let new_pos = (*ideal_cursor_column).min(max_cursor_pos); - state.set_current_cursor_pos(new_pos); - Ok("move down from functions/modes/read_only/auth_ro.rs".to_string()) + // Move to the next field within the canvas + let new_field = (current_field + 1).min(last_field_index); + state.set_current_field(new_field); + let current_input = state.get_current_input(); + let max_cursor_pos = if current_input.is_empty() { + 0 + } else { + current_input.len().saturating_sub(1) + }; + let new_pos = (*ideal_cursor_column).min(max_cursor_pos); + state.set_current_cursor_pos(new_pos); + Ok("".to_string()) // Clear previous debug message + } } "move_first_line" => { key_sequence_tracker.reset(); diff --git a/client/src/modes/canvas/read_only.rs b/client/src/modes/canvas/read_only.rs index 59a6aa5..9adfa62 100644 --- a/client/src/modes/canvas/read_only.rs +++ b/client/src/modes/canvas/read_only.rs @@ -6,11 +6,12 @@ use crate::services::grpc_client::GrpcClient; use crate::state::canvas_state::CanvasState; use crate::state::pages::auth::AuthState; use crate::state::pages::form::FormState; +use crate::state::state::AppState; use crate::functions::modes::read_only::{auth_ro, form_ro}; use crossterm::event::KeyEvent; pub async fn handle_read_only_event( - app_state: &crate::state::state::AppState, + app_state: &mut AppState, key: KeyEvent, config: &Config, form_state: &mut FormState, @@ -90,6 +91,7 @@ pub async fn handle_read_only_event( } else if app_state.ui.show_login { auth_ro::execute_action( action, + app_state, auth_state, ideal_cursor_column, key_sequence_tracker, @@ -136,6 +138,7 @@ pub async fn handle_read_only_event( } else if app_state.ui.show_login { auth_ro::execute_action( action, + app_state, auth_state, ideal_cursor_column, key_sequence_tracker, @@ -181,6 +184,7 @@ pub async fn handle_read_only_event( } else if app_state.ui.show_login { auth_ro::execute_action( action, + app_state, auth_state, ideal_cursor_column, key_sequence_tracker, diff --git a/client/src/modes/general/navigation.rs b/client/src/modes/general/navigation.rs index 8183d31..94752f3 100644 --- a/client/src/modes/general/navigation.rs +++ b/client/src/modes/general/navigation.rs @@ -4,6 +4,8 @@ use crossterm::event::KeyEvent; use crate::config::binds::config::Config; use crate::state::state::AppState; use crate::state::pages::form::FormState; +use crate::state::pages::auth::AuthState; +use crate::state::canvas_state::CanvasState; use crate::tui::functions::{intro, admin}; pub async fn handle_navigation_event( @@ -11,6 +13,7 @@ pub async fn handle_navigation_event( config: &Config, form_state: &mut FormState, app_state: &mut AppState, + auth_state: &mut AuthState, command_mode: &mut bool, command_input: &mut String, command_message: &mut String, @@ -18,7 +21,7 @@ pub async fn handle_navigation_event( if let Some(action) = config.get_general_action(key.code, key.modifiers) { match action { "move_up" => { - move_up(app_state); + move_up(app_state, auth_state); return Ok((false, String::new())); } "move_down" => { @@ -61,8 +64,16 @@ pub async fn handle_navigation_event( Ok((false, String::new())) } -pub fn move_up(app_state: &mut AppState) { - if app_state.ui.show_intro { +pub fn move_up(app_state: &mut AppState, auth_state: &mut AuthState) { + if app_state.ui.focus_outside_canvas && app_state.ui.show_login { + if app_state.general.selected_item == 0 { + app_state.ui.focus_outside_canvas = false; + let last_field_index = auth_state.fields().len().saturating_sub(1); + auth_state.set_current_field(last_field_index); + } else { + app_state.general.selected_item = app_state.general.selected_item.saturating_sub(1); + } + } else if app_state.ui.show_intro { app_state.ui.intro_state.previous_option(); } else if app_state.ui.show_admin { // Assuming profile_tree.profiles is the list we're navigating @@ -81,7 +92,12 @@ pub fn move_up(app_state: &mut AppState) { } pub fn move_down(app_state: &mut AppState) { - if app_state.ui.show_intro { + if app_state.ui.focus_outside_canvas && app_state.ui.show_login { + let num_general_elements = 2; + if app_state.general.selected_item < num_general_elements - 1 { + app_state.general.selected_item += 1; + } + } else if app_state.ui.show_intro { app_state.ui.intro_state.next_option(); } else if app_state.ui.show_admin { // Assuming profile_tree.profiles is the list we're navigating diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index d1e452f..697c3ca 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -76,6 +76,7 @@ impl EventHandler { config, form_state, app_state, + auth_state, &mut self.command_mode, &mut self.command_input, &mut self.command_message, @@ -154,7 +155,7 @@ impl EventHandler { } return read_only::handle_read_only_event( - &app_state, + app_state, key, config, form_state, diff --git a/client/src/modes/handlers/mode_manager.rs b/client/src/modes/handlers/mode_manager.rs index a8deba1..80e0f0f 100644 --- a/client/src/modes/handlers/mode_manager.rs +++ b/client/src/modes/handlers/mode_manager.rs @@ -19,6 +19,10 @@ impl ModeManager { return AppMode::Command; } + if app_state.ui.focus_outside_canvas { + return AppMode::General; + } + if app_state.ui.show_login { if event_handler.is_edit_mode { AppMode::Edit diff --git a/client/src/state/state.rs b/client/src/state/state.rs index 81c6036..84c3f41 100644 --- a/client/src/state/state.rs +++ b/client/src/state/state.rs @@ -21,6 +21,7 @@ pub struct UiState { pub show_form: bool, pub show_login: bool, pub intro_state: IntroState, + pub focus_outside_canvas: bool, pub dialog: DialogState, // Add dialog state here } @@ -139,6 +140,7 @@ impl Default for UiState { show_form: false, show_login: false, intro_state: IntroState::new(), + focus_outside_canvas: false, dialog: DialogState::default(), } }