centralizing logic in the formstate

This commit is contained in:
filipriec
2025-06-08 00:00:37 +02:00
parent dc232b2523
commit f9841f2ef3
4 changed files with 98 additions and 91 deletions

View File

@@ -82,21 +82,13 @@ pub async fn run_ui() -> Result<()> {
}
}
// Initialize AppState and FormState with table data
let (initial_profile, initial_table, initial_columns) =
let (initial_profile, initial_table, initial_columns_from_service) =
UiService::initialize_app_state_and_form(&mut grpc_client, &mut app_state)
.await
.context("Failed to initialize app state and form")?;
// Initialize AppState and FormState with table data
let (initial_profile, initial_table, initial_columns_from_service) = // Renamed for clarity
UiService::initialize_app_state_and_form(&mut grpc_client, &mut app_state)
.await
.context("Failed to initialize app state and form")?;
let filtered_columns = filter_user_columns(initial_columns_from_service);
// Filter the columns obtained from the service
let filtered_columns = filter_user_columns(initial_columns_from_service); // Use the correct variable
let mut form_state = FormState::new(
initial_profile.clone(),
initial_table.clone(),
@@ -110,7 +102,6 @@ pub async fn run_ui() -> Result<()> {
initial_profile, initial_table
))?;
// Load initial data for the form
if form_state.total_count > 0 {
if let Err(e) = UiService::load_table_data_by_position(&mut grpc_client, &mut form_state).await {
event_handler.command_message = format!("Error loading initial data: {}", e);
@@ -130,11 +121,9 @@ pub async fn run_ui() -> Result<()> {
let mut needs_redraw = true;
let mut prev_view_profile_name = app_state.current_view_profile_name.clone();
let mut prev_view_table_name = app_state.current_view_table_name.clone();
let mut table_just_switched = false;
loop {
// ===================================================================
// PROCESS EVENTS & UPDATE STATE
// ===================================================================
let position_before_event = form_state.current_position;
let mut event_processed = false;
if crossterm_event::poll(std::time::Duration::from_millis(1))? {
@@ -156,7 +145,6 @@ pub async fn run_ui() -> Result<()> {
&mut app_state,
).await;
// --- Handle the outcome of the event ---
let mut should_exit = false;
match event_outcome_result {
Ok(outcome) => match outcome {
@@ -205,7 +193,6 @@ pub async fn run_ui() -> Result<()> {
}
}
// --- Handle async results from other tasks ---
match login_result_receiver.try_recv() {
Ok(result) => {
if login::handle_login_result(result, &mut app_state, &mut auth_state, &mut login_state) {
@@ -255,11 +242,6 @@ pub async fn run_ui() -> Result<()> {
}
}
// ===================================================================
// STATE-DEPENDENT LOGIC (NOW RUNS AFTER STATE IS UPDATED)
// ===================================================================
// --- Determine which view is active ---
if let Some(active_view) = buffer_state.get_active_view() {
app_state.ui.show_intro = false;
app_state.ui.show_login = false;
@@ -307,55 +289,92 @@ pub async fn run_ui() -> Result<()> {
}
}
// --- Handle table change for FormView ---
if app_state.ui.show_form {
let current_view_profile = app_state.current_view_profile_name.clone();
let current_view_table = app_state.current_view_table_name.clone();
if prev_view_profile_name != current_view_profile || prev_view_table_name != current_view_table {
if let (Some(prof_name), Some(tbl_name)) = (current_view_profile.as_ref(), current_view_table.as_ref()) {
app_state.show_loading_dialog("Loading Table", &format!("Fetching data for {}.{}...", prof_name, tbl_name));
if prev_view_profile_name != current_view_profile
|| prev_view_table_name != current_view_table
{
if let (Some(prof_name), Some(tbl_name)) =
(current_view_profile.as_ref(), current_view_table.as_ref())
{
app_state.show_loading_dialog(
"Loading Table",
&format!("Fetching data for {}.{}...", prof_name, tbl_name),
);
needs_redraw = true;
match grpc_client.get_table_structure(prof_name.clone(), tbl_name.clone()).await {
match grpc_client
.get_table_structure(prof_name.clone(), tbl_name.clone())
.await
{
Ok(structure_response) => {
let new_columns: Vec<String> = structure_response.columns.iter().map(|c| c.name.clone()).collect();
let new_columns: Vec<String> = structure_response
.columns
.iter()
.map(|c| c.name.clone())
.collect();
// --- START FIX ---
// Apply the same filtering logic here that is used on initial load.
let filtered_columns = filter_user_columns(new_columns);
form_state = FormState::new(prof_name.clone(), tbl_name.clone(), filtered_columns);
// --- END FIX ---
form_state = FormState::new(
prof_name.clone(),
tbl_name.clone(),
filtered_columns,
);
if let Err(e) = UiService::fetch_and_set_table_count(&mut grpc_client, &mut form_state).await {
app_state.update_dialog_content(&format!("Error fetching count: {}", e), vec!["OK".to_string()], DialogPurpose::LoginFailed);
} else {
if form_state.total_count > 0 {
if let Err(e) = UiService::load_table_data_by_position(&mut grpc_client, &mut form_state).await {
app_state.update_dialog_content(&format!("Error loading data: {}", e), vec!["OK".to_string()], DialogPurpose::LoginFailed);
} else {
app_state.hide_dialog();
}
if let Err(e) = UiService::fetch_and_set_table_count(
&mut grpc_client,
&mut form_state,
)
.await
{
app_state.update_dialog_content(
&format!("Error fetching count: {}", e),
vec!["OK".to_string()],
DialogPurpose::LoginFailed,
);
} else if form_state.total_count > 0 {
if let Err(e) = UiService::load_table_data_by_position(
&mut grpc_client,
&mut form_state,
)
.await
{
app_state.update_dialog_content(
&format!("Error loading data: {}", e),
vec!["OK".to_string()],
DialogPurpose::LoginFailed,
);
} else {
form_state.reset_to_empty();
app_state.hide_dialog();
}
} else {
form_state.reset_to_empty();
app_state.hide_dialog();
}
prev_view_profile_name = current_view_profile;
prev_view_table_name = current_view_table;
table_just_switched = true;
}
Err(e) => {
app_state.update_dialog_content(&format!("Error fetching table structure: {}", e), vec!["OK".to_string()], DialogPurpose::LoginFailed);
app_state.current_view_profile_name = prev_view_profile_name.clone();
app_state.current_view_table_name = prev_view_table_name.clone();
app_state.update_dialog_content(
&format!("Error fetching table structure: {}", e),
vec!["OK".to_string()],
DialogPurpose::LoginFailed,
);
app_state.current_view_profile_name =
prev_view_profile_name.clone();
app_state.current_view_table_name =
prev_view_table_name.clone();
}
}
}
prev_view_profile_name = current_view_profile;
prev_view_table_name = current_view_table;
needs_redraw = true;
}
}
// --- Handle pending async fetches ---
if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() {
if app_state.ui.show_add_logic {
if admin_state.add_logic_state.profile_name == profile_name &&
@@ -414,28 +433,17 @@ pub async fn run_ui() -> Result<()> {
}
}
// --- Handle cursor updates based on position changes ---
let position_changed = form_state.current_position != position_before_event;
let mut position_logic_needs_redraw = false;
if app_state.ui.show_form {
if app_state.ui.show_form && !table_just_switched {
if position_changed && !event_handler.is_edit_mode {
let current_input_before_load = form_state.get_current_input();
let max_cursor_pos_before_load = if !current_input_before_load.is_empty() { current_input_before_load.chars().count() } else { 0 };
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos_before_load);
position_logic_needs_redraw = true;
if form_state.total_count > 0 && form_state.current_position > form_state.total_count + 1 {
form_state.current_position = form_state.total_count + 1;
} else if form_state.total_count == 0 && form_state.current_position > 1 {
form_state.current_position = 1;
}
if form_state.current_position == 0 && form_state.total_count > 0 {
form_state.current_position = 1;
}
if (form_state.total_count > 0 && form_state.current_position <= form_state.total_count && form_state.current_position > 0)
{
if form_state.current_position > form_state.total_count {
form_state.reset_to_empty();
event_handler.command_message = format!("New entry for {}.{}", form_state.profile_name, form_state.table_name);
} else {
match UiService::load_table_data_by_position(&mut grpc_client, &mut form_state).await {
Ok(load_message) => {
if event_handler.command_message.is_empty() || !load_message.starts_with("Error") {
@@ -446,27 +454,18 @@ pub async fn run_ui() -> Result<()> {
event_handler.command_message = format!("Error loading data: {}", e);
}
}
} else {
form_state.reset_to_empty();
event_handler.command_message = format!("New entry for {}.{}", form_state.profile_name, form_state.table_name);
}
let current_input_after_load_str = form_state.get_current_input();
let current_input_len_after_load = current_input_after_load_str.chars().count();
let max_cursor_pos_for_readonly_after_load = if current_input_len_after_load > 0 {
let max_cursor_pos = if current_input_len_after_load > 0 {
current_input_len_after_load.saturating_sub(1)
} else {
0
};
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
if event_handler.is_edit_mode {
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(current_input_len_after_load);
} else {
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos_for_readonly_after_load);
}
} else if !position_changed && !event_handler.is_edit_mode && app_state.ui.show_form {
} else if !position_changed && !event_handler.is_edit_mode {
let current_input_str = form_state.get_current_input();
let current_input_len = current_input_str.chars().count();
let max_cursor_pos = if current_input_len > 0 {
@@ -498,9 +497,6 @@ pub async fn run_ui() -> Result<()> {
needs_redraw = true;
}
// ===================================================================
// STEP 3: DRAW THE UI
// ===================================================================
if event_processed || needs_redraw || position_changed {
let current_mode = ModeManager::derive_mode(&app_state, &event_handler, &admin_state);
match current_mode {
@@ -543,12 +539,13 @@ pub async fn run_ui() -> Result<()> {
needs_redraw = false;
}
// --- FPS calculation ---
let now = Instant::now();
let frame_duration = now.duration_since(last_frame_time);
last_frame_time = now;
if frame_duration.as_secs_f64() > 1e-6 {
current_fps = 1.0 / frame_duration.as_secs_f64();
}
table_just_switched = false;
}
}