// src/state/app/state.rs use anyhow::Result; use common::proto::komp_ac::table_definition::ProfileTreeResponse; // NEW: Import the types we need for the cache use common::proto::komp_ac::table_structure::TableStructureResponse; use crate::modes::handlers::mode_manager::AppMode; use crate::search::state::SearchState; use crate::ui::handlers::context::DialogPurpose; use crate::config::binds::Config; use crate::pages::forms::FormState; use canvas::FormEditor; use crate::dialog::DialogState; use std::collections::HashMap; use std::env; use std::sync::Arc; #[cfg(feature = "ui-debug")] use std::time::Instant; pub struct UiState { pub show_sidebar: bool, pub show_buffer_list: bool, pub show_intro: bool, pub show_admin: bool, pub show_add_table: bool, pub show_add_logic: bool, pub show_form: bool, pub show_login: bool, pub show_register: bool, pub show_search_palette: bool, pub focus_outside_canvas: bool, pub dialog: DialogState, } #[cfg(feature = "ui-debug")] #[derive(Debug, Clone)] pub struct DebugState { pub displayed_message: String, pub is_error: bool, pub display_start_time: Instant, } pub struct AppState { // Core editor state pub current_dir: String, pub profile_tree: ProfileTreeResponse, pub selected_profile: Option, pub current_mode: AppMode, pub current_view_profile_name: Option, pub current_view_table_name: Option, // NEW: The "Rulebook" cache. We use Arc for efficient sharing. pub schema_cache: HashMap>, pub focused_button_index: usize, pub pending_table_structure_fetch: Option<(String, String)>, pub search_state: Option, // UI preferences pub ui: UiState, pub form_editor: Option>, #[cfg(feature = "ui-debug")] pub debug_state: Option, } impl AppState { pub fn new() -> Result { let current_dir = env::current_dir()?.to_string_lossy().to_string(); Ok(AppState { current_dir, profile_tree: ProfileTreeResponse::default(), selected_profile: None, current_view_profile_name: None, current_view_table_name: None, current_mode: AppMode::General, schema_cache: HashMap::new(), // NEW: Initialize the cache focused_button_index: 0, pending_table_structure_fetch: None, search_state: None, ui: UiState::default(), form_editor: None, #[cfg(feature = "ui-debug")] debug_state: None, }) } // --- ALL YOUR EXISTING METHODS ARE UNTOUCHED --- pub fn update_mode(&mut self, mode: AppMode) { self.current_mode = mode; } pub fn set_current_view_table(&mut self, profile_name: String, table_name: String) { self.current_view_profile_name = Some(profile_name); self.current_view_table_name = Some(table_name); } pub fn init_form_editor(&mut self, form_state: FormState, config: &Config) { let mut editor = FormEditor::new(form_state); editor.set_keymap(config.build_canvas_keymap()); // inject keymap self.form_editor = Some(editor); } /// Replace the current form state and wrap it in a FormEditor with keymap pub fn set_form_state(&mut self, form_state: FormState, config: &Config) { let mut editor = FormEditor::new(form_state); editor.set_keymap(config.build_canvas_keymap()); self.form_editor = Some(editor); } /// Immutable access to the underlying FormState pub fn form_state(&self) -> Option<&FormState> { self.form_editor.as_ref().map(|e| e.data_provider()) } /// Mutable access to the underlying FormState pub fn form_state_mut(&mut self) -> Option<&mut FormState> { self.form_editor.as_mut().map(|e| e.data_provider_mut()) } } impl Default for UiState { fn default() -> Self { Self { show_sidebar: false, show_intro: true, show_admin: false, show_add_table: false, show_add_logic: false, show_form: false, show_login: false, show_register: false, show_buffer_list: true, show_search_palette: false, // ADDED focus_outside_canvas: false, dialog: DialogState::default(), } } }