dialog login functionality

This commit is contained in:
filipriec
2025-04-10 15:36:43 +02:00
parent 3ed8764087
commit 6b241304fb
5 changed files with 39 additions and 25 deletions

View File

@@ -3,7 +3,8 @@
use crossterm::event::{Event, KeyCode}; use crossterm::event::{Event, KeyCode};
use crate::config::binds::config::Config; use crate::config::binds::config::Config;
use crate::state::state::AppState; use crate::state::state::AppState;
use crate::modes::handlers::event::EventOutcome; // Use EventOutcome from event handler use crate::modes::handlers::event::EventOutcome;
use crate::ui::handlers::context::DialogPurpose;
/// Handles key events specifically when a dialog is active. /// Handles key events specifically when a dialog is active.
/// Returns Some(Result<EventOutcome, Error>) if the event was handled (consumed), /// Returns Some(Result<EventOutcome, Error>) if the event was handled (consumed),
@@ -41,22 +42,16 @@ pub async fn handle_dialog_event(
} }
"select" => { "select" => {
let selected_index = app_state.ui.dialog.dialog_active_button_index; let selected_index = app_state.ui.dialog.dialog_active_button_index;
let selected_label = app_state.get_active_dialog_button_label().unwrap_or("").to_string(); let purpose = match app_state.ui.dialog.purpose {
let mut message = format!("Dialog '{}' selected", selected_label); Some(p) => p,
None => {
app_state.hide_dialog();
return Some(Ok(EventOutcome::Ok("Internal Error: Dialog context lost".to_string())));
}
};
// --- Add specific actions based on button index or label --- app_state.hide_dialog();
if selected_label.eq_ignore_ascii_case("menu") { return Some(Ok(EventOutcome::DialogAction { purpose, selected_index }));
app_state.ui.show_login = false;
app_state.ui.show_intro = true;
// focus_outside_canvas is handled by hide_dialog
message = "Returning to menu".to_string();
} else if selected_label.eq_ignore_ascii_case("exit") {
app_state.hide_dialog();
return Some(Ok(EventOutcome::Exit("Exiting via dialog".to_string())));
}
// --- End specific actions ---
app_state.hide_dialog(); // Hide dialog after processing selection
return Some(Ok(EventOutcome::Ok(message))); // Consume event
} }
_ => {} // Ignore other general actions when dialog is shown _ => {} // Ignore other general actions when dialog is shown
} }

View File

@@ -21,6 +21,7 @@ use crate::modes::{
use crate::config::binds::key_sequences::KeySequenceTracker; use crate::config::binds::key_sequences::KeySequenceTracker;
use crate::modes::handlers::mode_manager::{ModeManager, AppMode}; use crate::modes::handlers::mode_manager::{ModeManager, AppMode};
use crate::tui::functions::common::form::SaveOutcome; use crate::tui::functions::common::form::SaveOutcome;
use crate::ui::handlers::context::DialogPurpose;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventOutcome { pub enum EventOutcome {
@@ -28,6 +29,7 @@ pub enum EventOutcome {
Exit(String), Exit(String),
DataSaved(SaveOutcome, String), DataSaved(SaveOutcome, String),
ButtonSelected { context: UiContext, index: usize }, ButtonSelected { context: UiContext, index: usize },
DialogAction { purpose: DialogPurpose, selected_index: usize },
} }
pub struct EventHandler { pub struct EventHandler {

View File

@@ -4,6 +4,7 @@ use std::env;
use common::proto::multieko2::table_definition::ProfileTreeResponse; use common::proto::multieko2::table_definition::ProfileTreeResponse;
use crate::components::IntroState; use crate::components::IntroState;
use crate::modes::handlers::mode_manager::AppMode; use crate::modes::handlers::mode_manager::AppMode;
use crate::ui::handlers::context::DialogPurpose;
pub struct DialogState { pub struct DialogState {
pub dialog_show: bool, pub dialog_show: bool,
@@ -11,6 +12,7 @@ pub struct DialogState {
pub dialog_message: String, pub dialog_message: String,
pub dialog_buttons: Vec<String>, pub dialog_buttons: Vec<String>,
pub dialog_active_button_index: usize, pub dialog_active_button_index: usize,
pub purpose: Option<DialogPurpose>,
} }
pub struct UiState { pub struct UiState {
@@ -84,11 +86,13 @@ impl AppState {
title: &str, title: &str,
message: &str, message: &str,
buttons: Vec<String>, buttons: Vec<String>,
purpose: DialogPurpose,
) { ) {
self.ui.dialog.dialog_title = title.to_string(); self.ui.dialog.dialog_title = title.to_string();
self.ui.dialog.dialog_message = message.to_string(); self.ui.dialog.dialog_message = message.to_string();
self.ui.dialog.dialog_buttons = buttons; self.ui.dialog.dialog_buttons = buttons;
self.ui.dialog.dialog_active_button_index = 0; // Default to first button self.ui.dialog.dialog_active_button_index = 0;
self.ui.dialog.purpose = Some(purpose);
self.ui.dialog.dialog_show = true; self.ui.dialog.dialog_show = true;
self.ui.focus_outside_canvas = true; self.ui.focus_outside_canvas = true;
} }
@@ -100,6 +104,7 @@ impl AppState {
self.ui.dialog.dialog_message.clear(); self.ui.dialog.dialog_message.clear();
self.ui.dialog.dialog_buttons.clear(); self.ui.dialog.dialog_buttons.clear();
self.ui.dialog.dialog_active_button_index = 0; self.ui.dialog.dialog_active_button_index = 0;
self.ui.dialog.purpose = None;
self.ui.focus_outside_canvas = false; self.ui.focus_outside_canvas = false;
} }
@@ -150,11 +155,12 @@ impl Default for UiState {
impl Default for DialogState { impl Default for DialogState {
fn default() -> Self { fn default() -> Self {
Self { Self {
dialog_show: false, // Use new name dialog_show: false,
dialog_title: String::new(), // Use new name dialog_title: String::new(),
dialog_message: String::new(), // Use new name dialog_message: String::new(),
dialog_buttons: Vec::new(), // Use new name dialog_buttons: Vec::new(),
dialog_active_button_index: 0, // Use new name dialog_active_button_index: 0,
purpose: None,
} }
} }
} }

View File

@@ -3,8 +3,7 @@ use crate::services::auth::AuthClient;
use crate::state::pages::auth::AuthState; use crate::state::pages::auth::AuthState;
use crate::state::state::AppState; use crate::state::state::AppState;
use crate::state::canvas_state::CanvasState; use crate::state::canvas_state::CanvasState;
// Remove unused import if CanvasState is not directly used here use crate::ui::handlers::context::DialogPurpose;
// use crate::state::canvas_state::CanvasState;
/// Attempts to log the user in using the provided credentials via gRPC. /// Attempts to log the user in using the provided credentials via gRPC.
/// Updates AuthState and AppState on success or failure. /// Updates AuthState and AppState on success or failure.
@@ -51,6 +50,7 @@ pub async fn save(
"Login Success", "Login Success",
&success_message, &success_message,
vec!["Menu".to_string(), "Exit".to_string()], vec!["Menu".to_string(), "Exit".to_string()],
DialogPurpose::LoginSuccess,
); );
Ok("Login successful, details shown in dialog.".to_string()) Ok("Login successful, details shown in dialog.".to_string())
@@ -62,7 +62,8 @@ pub async fn save(
app_state.show_dialog( app_state.show_dialog(
"Login Failed", "Login Failed",
&error_message, &error_message,
vec!["OK".to_string()], // Pass buttons here vec!["OK".to_string()],
DialogPurpose::LoginFailed,
); );
// REMOVE these lines: // REMOVE these lines:
// app_state.ui.dialog.dialog_title = "Login Failed".to_string(); // app_state.ui.dialog.dialog_title = "Login Failed".to_string();

View File

@@ -1,3 +1,5 @@
// src/ui/handlers/context.rs
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UiContext { pub enum UiContext {
Intro, Intro,
@@ -6,3 +8,11 @@ pub enum UiContext {
Dialog, Dialog,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DialogPurpose {
LoginSuccess,
LoginFailed,
// TODO in the future:
// ConfirmQuit,
}