diff --git a/client/config.toml b/client/config.toml index 6900154..caa6bc6 100644 --- a/client/config.toml +++ b/client/config.toml @@ -13,6 +13,8 @@ toggle_sidebar = ["ctrl+t"] toggle_buffer_list = ["ctrl+b"] next_field = ["Tab"] prev_field = ["Shift+Tab"] +next_buffer = ["ctrl+l"] +previous_buffer = ["ctrl+h"] [keybindings.common] save = ["ctrl+s"] @@ -34,6 +36,8 @@ enter_edit_mode_before = ["i"] enter_edit_mode_after = ["a"] previous_entry = ["left","q"] next_entry = ["right","1"] +next_buffer = ["ctrl+l"] +previous_buffer = ["ctrl+h"] move_left = ["h"] move_right = ["l"] diff --git a/client/src/functions/common.rs b/client/src/functions/common.rs index cd77afe..0810b57 100644 --- a/client/src/functions/common.rs +++ b/client/src/functions/common.rs @@ -1,2 +1,5 @@ // src/functions/common.rs +pub mod buffer; + +pub use buffer::*; diff --git a/client/src/functions/common/buffer.rs b/client/src/functions/common/buffer.rs new file mode 100644 index 0000000..5d45c6e --- /dev/null +++ b/client/src/functions/common/buffer.rs @@ -0,0 +1,26 @@ +// src/functions/common/buffer.rs + +use crate::state::app::buffer::BufferState; + +/// Switches the active buffer index. +pub fn switch_buffer(buffer_state: &mut BufferState, next: bool) -> bool { + if buffer_state.history.len() <= 1 { + return false; + } + + let len = buffer_state.history.len(); + let current_index = buffer_state.active_index; + let new_index = if next { + (current_index + 1) % len + } else { + (current_index + len - 1) % len + }; + + if new_index != current_index { + buffer_state.active_index = new_index; + true + } else { + false + } +} + diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index 0df340c..ba4d15b 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -6,6 +6,7 @@ use crate::services::auth::AuthClient; use crate::config::binds::config::Config; use crate::ui::handlers::rat_state::UiStateHandler; use crate::ui::handlers::context::UiContext; +use crate::functions::common::buffer; use crate::tui::{ terminal::core::TerminalCore, functions::{ @@ -152,11 +153,28 @@ impl EventHandler { &mut self.command_message, ).await; match nav_outcome { + Ok(EventOutcome::Ok(ref msg)) if msg.is_empty() => { + if let Some(action) = config.get_general_action(key_code, modifiers) { + match action { + "next_buffer" => { + if buffer::switch_buffer(buffer_state, true) { + return Ok(EventOutcome::Ok("Switched to next buffer".to_string())); + } + } + "previous_buffer" => { + if buffer::switch_buffer(buffer_state, false) { + return Ok(EventOutcome::Ok("Switched to previous buffer".to_string())); + } + } + _ => {} + } + } + } Ok(EventOutcome::ButtonSelected { context, index }) => { let mut message = String::from("Selected"); // Default message match context { UiContext::Intro => { - intro::handle_intro_selection(app_state, index); + intro::handle_intro_selection(app_state, buffer_state, index); if app_state.ui.show_admin { let profile_names = app_state.profile_tree.profiles.iter() .map(|p| p.name.clone()) @@ -195,6 +213,24 @@ impl EventHandler { }, AppMode::ReadOnly => { + // --- Buffer Switching Check (ReadOnly Mode) --- + if let Some(action) = config.get_read_only_action_for_key(key_code, modifiers) { + match action { + "next_buffer" => { + if buffer::switch_buffer(buffer_state, true) { + return Ok(EventOutcome::Ok("Switched to next buffer".to_string())); + } + } + "previous_buffer" => { + if buffer::switch_buffer(buffer_state, false) { + return Ok(EventOutcome::Ok("Switched to previous buffer".to_string())); + } + } + _ => {} // Other read_only/common actions handled below + } + } + // --- End Buffer Switching Check --- + if config.is_enter_edit_mode_before(key_code, modifiers) && ModeManager::can_enter_edit_mode(current_mode) { self.is_edit_mode = true; diff --git a/client/src/tui/functions/intro.rs b/client/src/tui/functions/intro.rs index 309f5a7..de92f12 100644 --- a/client/src/tui/functions/intro.rs +++ b/client/src/tui/functions/intro.rs @@ -1,31 +1,33 @@ // src/tui/functions/intro.rs use crate::state::app::state::AppState; +use crate::state::app::buffer::{AppView, BufferState}; -pub fn handle_intro_selection(app_state: &mut AppState, index: usize) { - match index { // Use index directly - 0 => { // Continue - app_state.ui.show_form = true; - app_state.ui.show_admin = false; - app_state.ui.show_login = false; - } - 1 => { // Admin - app_state.ui.show_form = false; - app_state.ui.show_admin = true; - app_state.ui.show_login = false; - } - 2 => { // Login - app_state.ui.show_form = false; - app_state.ui.show_admin = false; - app_state.ui.show_login = true; - } - 3 => { // Register - app_state.ui.show_intro = false; - app_state.ui.show_register = true; - app_state.ui.focus_outside_canvas = false; - app_state.focused_button_index = 0; - } - _ => {} +/// Handles intro screen selection by updating view history and managing focus state. +/// 0: Continue (restores last form or default) +/// 1: Admin view +/// 2: Login view +/// 3: Register view (with focus reset) +pub fn handle_intro_selection( + app_state: &mut AppState, + buffer_state: &mut BufferState, + index: usize, +) { + let target_view = match index { + 0 => buffer_state.history.iter().rev() + .find(|v| matches!(v, AppView::Form(_))) + .cloned() + .unwrap_or_else(|| AppView::Form("Default".to_string())), + 1 => AppView::Admin, + 2 => AppView::Login, + 3 => AppView::Register, + _ => return, + }; + + buffer_state.update_history(target_view); + + // Register view requires focus reset + if index == 3 { + app_state.ui.focus_outside_canvas = false; + app_state.focused_button_index = 0; } - app_state.ui.show_intro = false; } - diff --git a/client/src/ui/handlers/ui.rs b/client/src/ui/handlers/ui.rs index e05e2d7..18e70dd 100644 --- a/client/src/ui/handlers/ui.rs +++ b/client/src/ui/handlers/ui.rs @@ -15,6 +15,7 @@ use crate::state::pages::auth::RegisterState; use crate::state::pages::admin::AdminState; use crate::state::pages::intro::IntroState; use crate::state::app::buffer::BufferState; +use crate::state::app::buffer::AppView; use crate::state::app::state::AppState; // Import SaveOutcome use crate::tui::terminal::{EventReader, TerminalCore}; @@ -54,6 +55,30 @@ pub async fn run_ui() -> Result<(), Box> { // Determine edit mode based on EventHandler state let is_edit_mode = event_handler.is_edit_mode; + // --- Synchronize UI View from Active Buffer --- + if let Some(active_view) = buffer_state.get_active_view() { + // Reset all flags first + app_state.ui.show_intro = false; + app_state.ui.show_login = false; + app_state.ui.show_register = false; + app_state.ui.show_admin = false; + app_state.ui.show_form = false; + // Potentially reset focus flag unless dialog is shown + if !app_state.ui.dialog.dialog_show { + app_state.ui.focus_outside_canvas = false; + } + + match active_view { + AppView::Intro => app_state.ui.show_intro = true, + AppView::Login => app_state.ui.show_login = true, + AppView::Register => app_state.ui.show_register = true, + AppView::Admin => app_state.ui.show_admin = true, + AppView::Form(_) => app_state.ui.show_form = true, + AppView::Scratch => {} // Or show a scratchpad component + } + } + // --- End Synchronization --- + terminal.draw(|f| { render_ui( f,