login waiting dialog works, THIS COMMIT NEEDS TO BE REFACTORED

This commit is contained in:
filipriec
2025-04-18 14:44:04 +02:00
parent 73d9a6367c
commit 2b37de3b4d
11 changed files with 276 additions and 175 deletions

View File

@@ -3,6 +3,7 @@
use crate::config::binds::config::Config;
use crate::config::colors::themes::Theme;
use crate::services::grpc_client::GrpcClient;
use crate::services::auth::AuthClient; // <-- Add AuthClient import
use crate::services::ui_service::UiService;
use crate::modes::common::commands::CommandHandler;
use crate::modes::handlers::event::{EventHandler, EventOutcome};
@@ -17,11 +18,15 @@ 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::ui::handlers::context::DialogPurpose; // <-- Add DialogPurpose import
// Import SaveOutcome
use crate::tui::terminal::{EventReader, TerminalCore};
use crate::ui::handlers::render::render_ui;
use crate::tui::functions::common::login; // <-- Add login module import
use std::time::Instant;
use crossterm::cursor::SetCursorStyle;
use crossterm::event as crossterm_event;
use log; // <-- Add log import
pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
let config = Config::load()?;
@@ -57,9 +62,6 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
let mut current_fps = 0.0;
loop {
// 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
@@ -87,6 +89,10 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
}
// --- End Synchronization ---
// --- 3. Draw UI ---
// Draw the current state *first*. This ensures the loading dialog
// set in the *previous* iteration gets rendered before the pending
// action check below.
terminal.draw(|f| {
render_ui(
f,
@@ -98,7 +104,7 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
&mut admin_state,
&buffer_state,
&theme,
is_edit_mode,
event_handler.is_edit_mode, // Use event_handler's state
&event_handler.highlight_state,
app_state.total_count,
app_state.current_position,
@@ -112,77 +118,103 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
})?;
// --- Cursor Visibility Logic ---
// (Keep existing cursor logic here - depends on state drawn above)
let current_mode = ModeManager::derive_mode(&app_state, &event_handler);
match current_mode {
AppMode::Edit => {
terminal.show_cursor()?;
}
AppMode::Highlight => {
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
terminal.show_cursor()?;
}
AppMode::Edit => { terminal.show_cursor()?; }
AppMode::Highlight => { terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; 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)?;
}
if !app_state.ui.focus_outside_canvas { terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; }
else { terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?; }
terminal.show_cursor()?;
}
AppMode::General => {
if app_state.ui.focus_outside_canvas {
terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?;
terminal.show_cursor()?;
} else {
terminal.hide_cursor()?;
}
}
AppMode::Command => {
terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?;
terminal.show_cursor()?;
if app_state.ui.focus_outside_canvas { terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?; terminal.show_cursor()?; }
else { terminal.hide_cursor()?; }
}
AppMode::Command => { terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?; terminal.show_cursor()?; }
}
// --- End Cursor Visibility Logic ---
let total_count = app_state.total_count; // Keep track for save logic
// --- 2. Check for Pending Login Action ---
// Check *after* drawing, so the loading state was rendered.
if login_state.login_request_pending {
// Reset the flag *before* calling save
login_state.login_request_pending = false;
// Create AuthClient and call save
match AuthClient::new().await {
Ok(mut auth_client_instance) => {
let save_result = login::save(
&mut auth_state,
&mut login_state,
&mut auth_client_instance,
&mut app_state,
).await;
match save_result {
Ok(msg) => log::info!("Login save result: {}", msg),
Err(e) => log::error!("Error during login save: {}", e),
}
}
Err(e) => {
// Handle connection error
app_state.show_dialog(
"Login Failed",
&format!("Connection Error: {}", e),
vec!["OK".to_string()],
DialogPurpose::LoginFailed,
);
login_state.error_message = Some(format!("Connection Error: {}", e));
log::error!("Failed to create AuthClient: {}", e);
}
}
// After save runs, the state (dialog content, etc.) is updated.
// The *next* iteration's draw call will show the final result.
} // --- End Pending Login Check ---
let total_count = app_state.total_count;
let mut current_position = app_state.current_position;
let position_before_event = current_position;
let event = event_reader.read_event()?;
// Get the outcome from the event handler
let event_outcome_result = event_handler
.handle_event(
event,
&config,
&mut terminal,
&mut grpc_client,
&mut command_handler,
&mut form_state,
&mut auth_state,
&mut login_state,
&mut register_state,
&mut intro_state,
&mut admin_state,
&mut buffer_state,
&mut app_state,
total_count,
&mut current_position,
)
.await;
// --- 1. Handle Terminal Events ---
let mut event_outcome_result = Ok(EventOutcome::Ok(String::new()));
// Poll for events *after* drawing and checking pending actions
if crossterm_event::poll(std::time::Duration::from_millis(20))? {
let event = event_reader.read_event()?;
event_outcome_result = event_handler
.handle_event(
event,
&config,
&mut terminal,
&mut grpc_client,
&mut command_handler,
&mut form_state,
&mut auth_state,
&mut login_state,
&mut register_state,
&mut intro_state,
&mut admin_state,
&mut buffer_state,
&mut app_state,
total_count,
&mut current_position,
)
.await;
}
// Update position based on handler's modification
// This happens *after* the event is handled
app_state.current_position = current_position;
// --- 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;
// Update command message only if event handling produced one
// Avoid overwriting messages potentially set by pending actions
// event_handler.command_message = message;
}
}
EventOutcome::Exit(message) => {
@@ -191,8 +223,6 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
}
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,
@@ -201,30 +231,26 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
)
.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
}
EventOutcome::ButtonSelected { context, index } => {
event_handler.command_message = "Internal error: Unexpected button state".to_string();
EventOutcome::ButtonSelected { context: _, index: _ } => {
// This case should ideally be fully handled within handle_event
// If initiate_login was called, it returned early.
// If not, the message was set and returned via Ok(message).
// Log if necessary, but likely no action needed here.
// log::warn!("ButtonSelected outcome reached main loop unexpectedly.");
}
},
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;
}
}
} // --- End Consequence Handling ---
// --- 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
// --- Position Change Handling (after outcome processing and pending actions) ---
let position_changed = app_state.current_position != position_before_event;
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();
@@ -295,7 +321,7 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
event_handler.ideal_cursor_column.min(max_cursor_pos);
}
} else if app_state.ui.show_register {
if !event_handler.is_edit_mode {
if !event_handler.is_edit_mode {
let current_input = register_state.get_current_input();
let max_cursor_pos = if !current_input.is_empty() {
current_input.len() - 1
@@ -305,7 +331,7 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
register_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
}
} else if app_state.ui.show_login {
if !event_handler.is_edit_mode {
if !event_handler.is_edit_mode {
let current_input = login_state.get_current_input();
let max_cursor_pos = if !current_input.is_empty() {
current_input.len() - 1
@@ -315,10 +341,10 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
login_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
}
}
// --- End Position Change Handling ---
// Check exit condition *after* processing outcome
// Check exit condition *after* all processing for the iteration
if should_exit {
// terminal.cleanup()?; // Optional: Drop handles this
return Ok(());
}
@@ -329,6 +355,6 @@ pub async fn run_ui() -> Result<(), Box<dyn std::error::Error>> {
if frame_duration.as_secs_f64() > 1e-6 {
current_fps = 1.0 / frame_duration.as_secs_f64();
}
}
} // End main loop
}