diff options
Diffstat (limited to 'src/ui/login.rs')
| -rw-r--r-- | src/ui/login.rs | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/ui/login.rs b/src/ui/login.rs new file mode 100644 index 0000000..8a85418 --- /dev/null +++ b/src/ui/login.rs @@ -0,0 +1,272 @@ +use eframe::egui; +use std::sync::mpsc::Receiver; + +use crate::api::ApiClient; +use crate::models::LoginResponse; +use crate::session::SessionManager; + +pub struct LoginScreen { + server_url: String, + username: String, + password: String, + + remember_server: bool, + remember_username: bool, + + error_message: Option<String>, + is_logging_in: bool, + + // For async operations + login_receiver: Option<Receiver<Result<(String, LoginResponse), String>>>, +} + +impl LoginScreen { + pub fn new(session_manager: &SessionManager) -> Self { + let server_url = session_manager + .get_saved_server_url() + .unwrap_or_else(|| "http://localhost:5777".to_string()); // Reminder to myself : Fucking remove this before release + + let username = session_manager.get_saved_username().unwrap_or_default(); + + let remember_username = !username.is_empty(); + + Self { + server_url, + username, + password: String::new(), + remember_server: true, + remember_username, + error_message: None, + is_logging_in: false, + login_receiver: None, + } + } + + pub fn show(&mut self, ctx: &egui::Context, on_success: &mut Option<(String, LoginResponse)>) { + // Check if we have a login result from async operation + if let Some(receiver) = &self.login_receiver { + match receiver.try_recv() { + Ok(result) => { + log::info!("UI thread: Received login result!"); + self.is_logging_in = false; + self.login_receiver = None; + + match result { + Ok((server_url, login_response)) => { + log::info!("UI thread: Login successful, setting on_success"); + *on_success = Some((server_url, login_response)); + } + Err(err) => { + log::error!("UI thread: Login failed: {} tried suicide yet maybe that actually works?", err); + self.error_message = Some(err); + } + } + } + Err(std::sync::mpsc::TryRecvError::Empty) => { + // Still waiting, request repaint to check again + ctx.request_repaint(); + } + Err(std::sync::mpsc::TryRecvError::Disconnected) => { + log::error!("UI thread: Channel disconnected!"); + self.is_logging_in = false; + self.login_receiver = None; + self.error_message = Some("Connection error".to_string()); + } + } + } + + egui::CentralPanel::default().show(ctx, |ui| { + // Center the login form both horizontally and vertically bruh + let available_size = ui.available_size(); + let panel_width = available_size.x.min(500.0); + + ui.allocate_ui_with_layout( + available_size, + egui::Layout::top_down(egui::Align::Center), + |ui| { + // Add vertical spacing to center + ui.add_space(available_size.y * 0.15); + + // Logo/Title + ui.heading(egui::RichText::new("BeepZone Login").size(48.0).strong()); + ui.label( + egui::RichText::new(format!( + "BeepZone Desktop Client eGUI EMO Edition - v{}", + env!("CARGO_PKG_VERSION") + )) + .size(18.0), + ); + + ui.add_space(30.0); + + // Login form + egui::Frame::new() + .fill(ctx.style().visuals.window_fill) + .stroke(ctx.style().visuals.window_stroke) + .corner_radius(12.0) + .inner_margin(32.0) + .show(ui, |ui| { + ui.set_width(panel_width * 0.8); + + // Server URL + ui.horizontal(|ui: &mut egui::Ui| { + ui.label("BeepZone Sekel API URL:"); + ui.add_space(10.0); + }); + ui.text_edit_singleline(&mut self.server_url); + ui.add_space(8.0); + + // Username field + ui.label("Username:"); + ui.text_edit_singleline(&mut self.username); + ui.add_space(8.0); + + // Password field + ui.label("Password:"); + let password_response = ui + .add(egui::TextEdit::singleline(&mut self.password).password(true)); + + // Enter key to submit + if password_response.lost_focus() + && ui.input(|i| i.key_pressed(egui::Key::Enter)) + { + self.do_login(); + } + + ui.add_space(12.0); + + // Remember options + ui.checkbox(&mut self.remember_server, "Remember Sekel URL"); + ui.checkbox(&mut self.remember_username, "Remember Username"); + + ui.add_space(16.0); + + // Error message + if let Some(error) = &self.error_message { + ui.label(format!("Error: {}", error)); + ui.add_space(12.0); + } + + // Login button + ui.add_enabled_ui(!self.is_logging_in, |ui| { + let button_text = if self.is_logging_in { + "Logging in..." + } else { + "Login" + }; + + if ui + .add_sized( + [ui.available_width(), 40.0], + egui::Button::new(button_text), + ) + .clicked() + { + self.do_login(); + } + }); + + if self.is_logging_in { + ui.add_space(8.0); + ui.horizontal(|ui| { + ui.spinner(); + ui.label("Connecting to server..."); + }); + } + }); + + ui.add_space(20.0); + ui.label( + egui::RichText::new("- The only based Sigma Inventory System -") + .size(12.0) + .color(egui::Color32::GRAY), + ); + + // Debug info + if self.is_logging_in { + ui.add_space(10.0); + ui.label( + egui::RichText::new(format!("Connecting to: {}", self.server_url)) + .size(10.0) + .color(egui::Color32::GRAY), + ); + } + }, + ); + }); + } + + fn do_login(&mut self) { + // Validate inputs + if self.server_url.trim().is_empty() { + self.error_message = + Some("Server URL is required!? Perhaps enter it you know?".to_string()); + return; + } + + if self.username.trim().is_empty() || self.password.trim().is_empty() { + self.error_message = Some( + "Username and password are required!? Please enter both you know?".to_string(), + ); + return; + } + + self.error_message = None; + self.is_logging_in = true; + + // Clone data for background thread + let server_url = self.server_url.clone(); + let username = self.username.clone(); + let password = self.password.clone(); + + log::info!("Trying to sign in as : {}", username); + + // Create channel for communication + let (tx, rx) = std::sync::mpsc::channel(); + self.login_receiver = Some(rx); + + // Spawn background thread to perform login + std::thread::spawn(move || { + log::info!("Background thread: Connecting to {}", server_url); + let result = match ApiClient::new(server_url.clone()) { + Ok(client) => { + log::info!("Background thread: API client created, attempting login..."); + match client.login_password(&username, &password) { + Ok(response) => { + log::info!( + "Background thread: Got response, success={}", + response.success + ); + if response.success { + log::info!( + "Login successfulf for user: {}", + response.user.username + ); + Ok((server_url, response)) + } else { + let error = "Login failed gay credentials".to_string(); + log::error!("{}", error); + Err(error) + } + } + Err(e) => { + let error = format!("Notwork error: {}", e); + log::error!("{}", error); + Err(error) + } + } + } + Err(e) => { + let error = format!("Failed at connecting to server somehow: {}", e); + log::error!("{}", error); + Err(error) + } + }; + + log::info!("Background thread: Sending result back to UI"); + if let Err(e) = tx.send(result) { + log::error!("Background thread: Failed to send result: {:?}", e); + } + }); + } +} |
