BREAKING CHANGES updating gRPC based on the enum now

This commit is contained in:
filipriec
2025-04-07 21:27:01 +02:00
parent bb103fac6c
commit 70678432c6
7 changed files with 316 additions and 182 deletions

View File

@@ -1,26 +1,25 @@
// src/ui/handlers/ui.rs
use crate::tui::terminal::TerminalCore;
use crate::config::binds::config::Config;
use crate::config::colors::themes::Theme;
use crate::modes::common::commands::CommandHandler;
use crate::modes::handlers::event::{EventHandler, EventOutcome}; // Import EventOutcome
use crate::modes::handlers::mode_manager::{AppMode, ModeManager};
use crate::services::grpc_client::GrpcClient;
use crate::services::ui_service::UiService;
use crate::tui::terminal::EventReader;
use crate::modes::common::commands::CommandHandler;
use crate::modes::handlers::mode_manager::{AppMode, ModeManager};
use crate::config::colors::themes::Theme;
use crate::config::binds::config::Config;
use crate::ui::handlers::render::render_ui;
use crate::state::pages::form::FormState;
use crate::state::pages::auth::AuthState;
use crate::state::canvas_state::CanvasState;
use crate::modes::handlers::event::EventHandler;
use crate::state::pages::auth::AuthState;
use crate::state::pages::form::FormState;
use crate::state::state::AppState;
use crate::tui::functions::common::form::SaveOutcome; // Import SaveOutcome
use crate::tui::terminal::{EventReader, TerminalCore};
use crate::ui::handlers::render::render_ui;
use crossterm::cursor::SetCursorStyle;
pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
let config = Config::load()?;
let mut terminal = TerminalCore::new()?;
let mut grpc_client = GrpcClient::new().await?;
// let auth_client = AuthClient::new().await?; // AuthClient is now inside EventHandler
let mut command_handler = CommandHandler::new();
let theme = Theme::from_str(&config.colors.theme);
let mut auth_state = AuthState::default(); // The single source of truth for AuthState
@@ -29,7 +28,9 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
let mut app_state = AppState::new()?;
// Initialize app state with profile tree and table structure
let column_names = UiService::initialize_app_state(&mut grpc_client, &mut app_state).await?;
let column_names =
UiService::initialize_app_state(&mut grpc_client, &mut app_state)
.await?;
// Initialize FormState with dynamic fields
let mut form_state = FormState::new(column_names);
@@ -39,7 +40,8 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
let event_reader = EventReader::new();
// Fetch the total count of Adresar entries
UiService::initialize_adresar_count(&mut grpc_client, &mut app_state).await?;
UiService::initialize_adresar_count(&mut grpc_client, &mut app_state)
.await?;
form_state.reset_to_empty();
loop {
@@ -63,97 +65,158 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
);
})?;
// --- Cursor Visibility Logic ---
let current_mode = ModeManager::derive_mode(&app_state, &event_handler);
match current_mode {
AppMode::Edit => {
terminal.show_cursor()?;
}
AppMode::ReadOnly => {
if !app_state.ui.focus_outside_canvas {
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
} else {
terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?;
}
terminal.show_cursor()?; // Ensure visible
}
AppMode::General | AppMode::Command => {
terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?;
terminal.show_cursor()?; // Ensure visible (though might not be positioned meaningfully)
}
}
// --- End Cursor Visibility Logic ---
let total_count = app_state.total_count;
// --- Cursor Visibility Logic ---
let current_mode = ModeManager::derive_mode(&app_state, &event_handler);
match current_mode {
AppMode::Edit => {
terminal.show_cursor()?;
}
AppMode::ReadOnly => {
if !app_state.ui.focus_outside_canvas {
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
} else {
terminal
.set_cursor_style(SetCursorStyle::SteadyUnderScore)?;
}
terminal.show_cursor()?; // Ensure visible
}
AppMode::General | AppMode::Command => {
terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?;
terminal.show_cursor()?; // Ensure visible (though might not be positioned meaningfully)
}
}
// --- End Cursor Visibility Logic ---
let total_count = app_state.total_count; // Keep track for save logic
let mut current_position = app_state.current_position;
// Store position before event handling to detect navigation
let position_before_event = current_position;
let event = event_reader.read_event()?;
let (should_exit, message) = event_handler.handle_event(
event,
&config,
&mut terminal,
&mut grpc_client,
&mut command_handler,
&mut form_state,
&mut auth_state, // Pass the single AuthState instance here too
&mut app_state,
total_count,
&mut current_position,
).await?;
// Get the outcome from the event handler
let event_outcome_result = event_handler
.handle_event(
event,
&config,
&mut terminal, // Pass terminal mutably
&mut grpc_client,
&mut command_handler,
&mut form_state,
&mut auth_state,
&mut app_state,
total_count, // Pass the count *before* potential save
&mut current_position,
)
.await;
// Update position based on handler's modification
app_state.current_position = current_position;
let position_changed = app_state.current_position != position_before_event;
// --- Centralized Consequence Handling ---
let mut should_exit = false;
match event_outcome_result {
// Handle the Result first
Ok(outcome) => match outcome {
// Handle the Ok variant containing EventOutcome
EventOutcome::Ok(message) => {
if !message.is_empty() {
event_handler.command_message = message;
}
}
EventOutcome::Exit(message) => {
event_handler.command_message = message;
should_exit = true;
}
EventOutcome::DataSaved(save_outcome, message) => {
event_handler.command_message = message; // Show save status
// *** Delegate outcome handling to UiService ***
if let Err(e) = UiService::handle_save_outcome(
save_outcome,
&mut grpc_client,
&mut app_state,
&mut form_state,
)
.await
{
// Handle potential errors from the outcome handler itself
event_handler.command_message =
format!("Error handling save outcome: {}", e);
}
// No count update needed for UpdatedExisting or NoChange
}
},
Err(e) => {
// Handle errors from handle_event, e.g., log or display
event_handler.command_message = format!("Error: {}", e);
// Decide if the error is fatal, maybe set should_exit = true;
}
}
// --- Position Change Handling (after outcome processing) ---
let position_changed =
app_state.current_position != position_before_event; // Calculate after potential update
// Recalculate total_count *after* potential update
let current_total_count = app_state.total_count;
// Handle position changes and update form state (Only when form is shown)
if app_state.ui.show_form {
if position_changed && !event_handler.is_edit_mode {
let current_input = form_state.get_current_input();
let max_cursor_pos = if !current_input.is_empty() {
current_input.len() - 1 // Limit to last character in readonly mode
current_input.len() - 1 // Limit to last character in readonly mode
} else {
0
};
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
form_state.current_cursor_pos =
event_handler.ideal_cursor_column.min(max_cursor_pos);
// Ensure position never exceeds total_count + 1
if app_state.current_position > total_count + 1 {
app_state.current_position = total_count + 1;
if app_state.current_position > current_total_count + 1 {
app_state.current_position = current_total_count + 1;
}
if app_state.current_position > total_count {
if app_state.current_position > current_total_count {
// New entry - reset form
form_state.reset_to_empty();
form_state.current_field = 0;
} else if app_state.current_position >= 1 && app_state.current_position <= total_count {
} else if app_state.current_position >= 1
&& app_state.current_position <= current_total_count
{
// Existing entry - load data
let current_position_to_load = app_state.current_position; // Use a copy
let load_message = UiService::load_adresar_by_position(
&mut grpc_client,
&mut app_state, // Pass app_state mutably if needed by the service
&mut form_state,
current_position_to_load
).await?;
current_position_to_load,
)
.await?;
let current_input = form_state.get_current_input();
let max_cursor_pos = if !event_handler.is_edit_mode && !current_input.is_empty() {
current_input.len() - 1 // In readonly mode, limit to last character
let max_cursor_pos = if !event_handler.is_edit_mode
&& !current_input.is_empty()
{
current_input.len() - 1 // In readonly mode, limit to last character
} else {
current_input.len()
};
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
form_state.current_cursor_pos = event_handler
.ideal_cursor_column
.min(max_cursor_pos);
// Don't overwrite message from handle_event if load_message is simple success
if !load_message.starts_with("Loaded entry") || message.is_empty() {
event_handler.command_message = load_message;
if !load_message.starts_with("Loaded entry")
|| event_handler.command_message.is_empty()
{
event_handler.command_message = load_message;
}
} else {
// Invalid position (e.g., 0) - reset to first entry or new entry mode
app_state.current_position = 1.min(total_count + 1); // Go to 1 or new entry if empty
if app_state.current_position > total_count {
form_state.reset_to_empty();
form_state.current_field = 0;
}
app_state.current_position =
1.min(current_total_count + 1); // Go to 1 or new entry if empty
if app_state.current_position > total_count {
form_state.reset_to_empty();
form_state.current_field = 0;
}
}
} else if !position_changed && !event_handler.is_edit_mode {
// If position didn't change but we are in read-only, just adjust cursor
@@ -163,29 +226,26 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
} else {
0
};
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
form_state.current_cursor_pos =
event_handler.ideal_cursor_column.min(max_cursor_pos);
}
} else if app_state.ui.show_login {
// Handle cursor updates for AuthState if needed, similar to FormState
if !event_handler.is_edit_mode {
let current_input = auth_state.get_current_input();
let max_cursor_pos = if !current_input.is_empty() {
current_input.len() - 1
} else {
0
};
auth_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
}
}
// Only update command message if handle_event provided one
if !message.is_empty() {
event_handler.command_message = message;
// Handle cursor updates for AuthState if needed, similar to FormState
if !event_handler.is_edit_mode {
let current_input = auth_state.get_current_input();
let max_cursor_pos = if !current_input.is_empty() {
current_input.len() - 1
} else {
0
};
auth_state.current_cursor_pos =
event_handler.ideal_cursor_column.min(max_cursor_pos);
}
}
// Check exit condition *after* processing outcome
if should_exit {
// terminal.cleanup()?; // Optional: Drop handles this
return Ok(());
}
}